How to Refactor a Switch Statement with Object Composition in Angular
Using Creational Patterns like Factory Method to refactor switch statements in Angular

Programmers try to avoid switch statements because switches break the rule of the Open-Closed-Principle. Also, continuously extending the switch statement with more clauses leads to a high maintenance effort, as we need to modify the written code every time we extend it. Maybe our working unit tests will fail after the change. We might need to fix our business logic and tests every time — what a nightmare…
“The Problem with such duplicate switches is that, whenever you add a clause, you have to find all the switches and update them.” (Martin Fowler, [Refactoring])
Why do we use switch statements?
We use them because switch statements work the way our brain works. If we have to implement a selection of different things — like a selection of themes, or types of tea/coffee we want to cook, or a selection of cars we want to buy with our saved money — the logical way is to implement different junctions to map all the possibilities: we code like a flow.
Example code
In Angular, using an HTML element like <select> seduces us to handle it with switch statements to check the chosen value. Let us take a list of themes as an example:
<div class="container">
<h1>Select theme with switch statement</h1>
<mat-form-field appearance="fill">
<mat-label>Theme selection</mat-label>
<mat-select [(ngModel)]="selectedTheme" (selectionChange)="selectionChanged()">
<mat-option value="dark">dark theme</mat-option>
<mat-option value="light">light theme</mat-option>
<mat-option value="red">red theme</mat-option>
<mat-option value="green">green theme</mat-option>
</mat-select>
</mat-form-field>
</div>Additionally to the HTML code, we need to implement a controller as follows:
public selectionChanged() {
switch (this.selectedTheme): void {
case 'dark':
console.log('changed theme to dark');
// do something more with the theme
break;
case 'light':
console.log('changed theme to light');
// do something more with the theme
break;
case 'red':
console.log('changed theme to red');
// do something more with the theme
break;
case 'green':
console.log('changed theme to green');
// do something more with the theme
break;
default:
console.log('What ever..');
}
}As we can see, we cover all cases of the selection inside the switch statement and implement some logic to see the output in the development console.
If we want to add more themes, we have to change the existing switch statement — more precisely: we have to modify the existing code. If we have more switch statements in other modules using the current selectedTheme (maybe as a parameter), we need to add the new case there, too. We have to comb the entire codebase for switch statements regarding the theme.
Time wasting? Error-prone, isn’t it?

Is there a better way?
Of course — Object Composition is a nice method for refactoring switch statements and making our code more flexible and decoupled. Because we abstract a simple use case into a complex and easy-to-handle software design principle (in our case: a pattern), it reduces the maintenance effort and makes it more reusable. Sometimes it is tough to find the right way and the suitable software architecture — but with more practice in Design Patterns and Software Architecture, it could be easy.
If we want to know more about Object Composition and Code Reuse in Angular, scroll to the Learn More section below.
Object Composition & Factory Method
Object Composition can help. Regarding the theme example, we only need to abstract the use case of the feature —managing themes, and classes of themes. So, why using string attributes and no real classes? We can, for example, couple these concrete classes with an interface or an abstract class at design time:

Here are the concrete theme classes based on the interface above:

Now we can design a factory for every concrete theme class, coupled with an abtract creator class to hide the logic from the client. Something like this:

Now look, we implemented the Factory Method Pattern of the “Design Pattern” by GoF.
This construct is easily scalable when we want to add more themes. In this case, we only need to create one more theme class and a creator class. We do not need to touch any code we have written before. We do not need to change any tests we have implemented yet. We comply with the Open-Closed-Principle.
The final code
So, let us show how the code looks if we implement this principle in Angular (from UML to code).
First of all, we need a theme interface and some concrete models:
// theme.interface.ts
export interface Theme {
name: string;
getStylename(): string;
getFontname(): string;
}// theme.model.ts
export class DarkTheme implements Theme {
public name = 'dark';
public getStylename(): string {
return this.name;
}
public getFontname(): string {
return 'Arial';
}
}
export class LightTheme implements Theme {
public name = 'light';
public getStylename(): string {
return this.name;
}
public getFontname(): string {
return 'Comic Sans MS';
}
}
// any other themesAdditionally, we need to implement our abstract creator class and the inherited concrete creator classes:
// theme.creator.ts
import { DarkTheme, LightTheme, RedTheme, Theme } from './theme.model';
export abstract class ThemeCreator {
public abstract factoryMethod(): Theme;
}
export class DarkThemeCreator extends ThemeCreator {
public factoryMethod(): Theme {
return new DarkTheme();
}
}
export class LightThemeCreator extends ThemeCreator {
public factoryMethod(): Theme {
return new LightTheme();
}
}
// any other creator classesTo help us to encapsulate the different architecture levels, we can implement a facade-like helper unit, where we create the other theme objects. The function addAvailableThemesToList is the only one we need to extend, if we want to add new themes — we will add them to an array.
// theme.facade.ts
import { DarkThemeCreator, LightThemeCreator, RedThemeCreator, ThemeCreator } from './theme.creator';
import { Theme } from './theme.model';
export function addAvailableThemesToList(): Theme[] {
return [
clientCode(new DarkThemeCreator()),
clientCode(new LightThemeCreator()),
clientCode(new RedThemeCreator())
];
}
function clientCode(creator: ThemeCreator): Theme {
return creator.factoryMethod();
}Finally, we integrate it into our Angular Component, which receives the themes from the facade-like unit. So, we do not need the switch statement anymore and got a very CLEAN component.
// theming-with-factory-method.component.ts
export class ThemingWithFactoryMethodComponent implements OnInit {
public selectedTheme: Theme;
public themes: Theme[];
constructor() {
this.themes = new Array<Theme>();
}
ngOnInit(): void {
this.themes = addAvailableThemesToList();
}
public selectionChanged(): void {
// read abstract class
console.log('changed theme to ' + this.selectedTheme.name);
}
public trackByFn(index, item: Theme): string {
return item.name;
}
}Regardingthe controller, the view looks like this:
<div class="container">
<h1>Select attribute with factory method</h1>
<mat-form-field appearance="fill">
<mat-label>Theme selection</mat-label>
<mat-select [(ngModel)]="selectedTheme" (selectionChange)="selectionChanged()">
<mat-option *ngFor="let theme of themes; trackBy: trackByFn" [value]="theme">
{{ theme.name }}
</mat-option>
</mat-select>
</mat-form-field>
</div>We see there is no ngSwitch either. We comply with the Open-Closed-Principle with a simple Factory Method. We have got only one place where the themes are created. The component doesn’t know all operations of the business logic. Its only responsibility is to receive the themes and show them to the user. That is all.
Conclusion
With the family of creational patterns, especially the Factory Method Pattern of this example, we can refactor switch statements to comply with the Open-Closed-Principle.
Another way to refactor switches is polymorphism. Martin Fowler describes some excellent examples in his book “Refactoring” about that. Take a look.
Thanks for reading! Follow me on Medium, Twitter, or Instagram, or subscribe here on Medium to read more about DevOps, Agile & Development Principles, Angular, and other useful stuff. Happy Coding! :)






