Angular Design Patterns
Design patterns provide solutions to common software design problems and help developers create scalable and maintainable applications. This guide covers various design patterns used in Angular applications.
Singleton Pattern
The Singleton pattern ensures that a class has only one instance and provides a global point of access to it. In Angular, services are singletons by default when provided in the root:
// my-service.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class MyService {
private static instance: MyService;
private constructor() {
if (MyService.instance) {
throw new Error('You can only create one instance!');
}
MyService.instance = this;
}
// Service methods here
}
Factory Pattern
The Factory pattern provides a way to create objects without specifying the exact class of object that will be created. In Angular, you can use factories for dependency injection:
// my-factory.ts
import { InjectionToken } from '@angular/core';
export const MY_SERVICE_TOKEN = new InjectionToken('MY_SERVICE_TOKEN');
export function myServiceFactory() {
return new MyService();
}
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { MY_SERVICE_TOKEN, myServiceFactory } from './my-factory';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [{ provide: MY_SERVICE_TOKEN, useFactory: myServiceFactory }],
bootstrap: [AppComponent]
})
export class AppModule { }
Observer Pattern
The Observer pattern allows objects to be notified of changes in other objects. In Angular, you can use RxJS observables to implement the Observer pattern:
// my-service.service.ts
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class MyService {
private subject = new Subject();
emit(value: any) {
this.subject.next(value);
}
getObservable() {
return this.subject.asObservable();
}
}
// my-component.component.ts
import { Component, OnInit } from '@angular/core';
import { MyService } from './my-service.service';
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent implements OnInit {
constructor(private myService: MyService) {}
ngOnInit() {
this.myService.getObservable().subscribe(value => {
console.log('Received value:', value);
});
}
emitValue() {
this.myService.emit('Hello, Observer Pattern!');
}
}
Decorator Pattern
The Decorator pattern allows behavior to be added to an individual object, dynamically. In Angular, decorators are used to attach metadata to classes, methods, and properties:
// my-component.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent {
// Component logic here
}
Facade Pattern
The Facade pattern provides a simplified interface to a complex subsystem. In Angular, you can create a facade service to encapsulate complex logic and provide a simple API:
// my-facade.service.ts
import { Injectable } from '@angular/core';
import { MyService } from './my-service.service';
@Injectable({
providedIn: 'root'
})
export class MyFacadeService {
constructor(private myService: MyService) {}
doSomething() {
// Complex logic
this.myService.emit('Facade Pattern');
}
}
// my-component.component.ts
import { Component, OnInit } from '@angular/core';
import { MyFacadeService } from './my-facade.service';
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent implements OnInit {
constructor(private myFacade: MyFacadeService) {}
ngOnInit() {
this.myFacade.doSomething();
}
}
Key Points
- Design patterns provide solutions to common software design problems.
- The Singleton pattern ensures a class has only one instance and provides a global point of access to it.
- The Factory pattern provides a way to create objects without specifying the exact class of object that will be created.
- The Observer pattern allows objects to be notified of changes in other objects using RxJS observables.
- The Decorator pattern adds behavior to an individual object dynamically using Angular decorators.
- The Facade pattern provides a simplified interface to a complex subsystem.
Conclusion
Using design patterns in Angular helps you build scalable and maintainable applications. By implementing patterns such as Singleton, Factory, Observer, Decorator, and Facade, you can solve common design problems and improve the structure of your code. Happy coding!