Cada clase o componente debe tener una única responsabilidad. En el contexto de Angular, esto significa que un componente debe estar enfocado en una única tarea o funcionalidad. Por ejemplo, un componente de Angular debería ser responsable de presentar datos en la interfaz de usuario y no debería encargarse también de manejar la lógica de negocio.
// Ejemplo de un componente Angular que viola el principio de responsabilidad única
@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {
products: Product[];
constructor(private productService: ProductService) { }
ngOnInit(): void {
this.products = this.productService.getProducts();
// Aquí se debería realizar únicamente la obtención de datos,
// pero también se podría realizar aquí la lógica de filtrado o ordenamiento, violando el principio de responsabilidad única.
}
}Las entidades de software (clases, módulos, etc.) deben estar abiertas para extensión pero cerradas para modificación. En Angular, esto se puede lograr mediante el uso de patrones como la inyección de dependencias y la extensibilidad de componentes y servicios mediante herencia o interfaces.
// Ejemplo de un servicio Angular que sigue el principio de abierto/cerrado
@Injectable()
export class ProductService {
constructor(private http: HttpClient) {}
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>('api/products');
}
}Los objetos de un programa deben ser reemplazables por instancias de sus subtipos sin alterar la corrección del programa. En Angular, esto se relaciona con la creación de clases y componentes que puedan ser extendidos o reemplazados por subclases sin afectar el comportamiento esperado del sistema.
// Ejemplo de clases en Angular que siguen el principio de sustitución de Liskov
class Animal {
makeSound(): void {}
}
class Dog extends Animal {
makeSound(): void {
console.log('Woof!');
}
}
class Cat extends Animal {
makeSound(): void {
console.log('Meow!');
}
}Los clientes no deben verse obligados a depender de interfaces que no utilizan. En Angular, esto significa que los componentes y servicios deben proporcionar interfaces claras y específicas para su funcionalidad, evitando interfaces demasiado amplias que obliguen a los consumidores a depender de funcionalidad no utilizada.
// Ejemplo de una interfaz en Angular que sigue el principio de segregación de la interfaz
interface Product {
id: number;
name: string;
price: number;
}
interface Order {
id: number;
products: Product[];
total: number;
}
// En lugar de tener una única interfaz "Order" que contenga toda la información sobre el pedido,
// podríamos dividirlo en interfaces más pequeñas y específicas según su uso.Los módulos de alto nivel no deben depender de módulos de bajo nivel. Ambos deben depender de abstracciones. En Angular, esto se logra mediante la inyección de dependencias, donde los componentes de alto nivel dependen de abstracciones (interfaces o clases base) en lugar de implementaciones concretas. Esto facilita la sustitución de implementaciones y hace que el código sea más flexible y mantenible.
// Ejemplo de un componente Angular que sigue el principio de inversión de dependencia
@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {
products: Product[];
constructor(private productService: ProductService) {}
ngOnInit(): void {
this.products = this.productService.getProducts();
}
}