一、单一职责原则
单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。
单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关实践经验。
简单的说就是一个类只负责单一功能职责。
二、开闭原则
开闭原则(Open-Closed Principle, OCP):一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
例子:
interface IBook {
getName(): string;
getPrice(): number;
getAuthor(): string;
}
class BookBase {
}
class NovelBook implements IBook {
protected name: string;
protected price: number;
protected author: string;
public getName() {
return this.name;
}
public getPrice() {
return this.price;
}
public getAuthor () {
return this.author;
}
}
class ComputerBoot implements IBook {
protected name: string;
protected price: number;
protected author: string;
public getName() {
return this.name;
}
public getPrice() {
return this.price;
}
public getAuthor () {
return this.author;
}
}
class BookStore {
private books: IBook[];
constructor() {
this.books = [];
}
public add(book: IBook) {
this.books.push(book);
}
public showOwnBooks() {
for(let book of this.books) {
console.log(`书名:${book.getName()},作者:${book.getAuthor()},价格:${book.getPrice}`);
}
}
}
例子的思路上网上看到的
三.里氏替换原则
里氏代换原则(Liskov Substitution Principle, LSP):所有引用基类(父类)的地方必须能透明地使用其子类的对象。
在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法。
例子:
abstract class AbstractGun {
abstract shoot(): void;
}
class HandGun extends AbstractGun {
public shoot() {
console.log('aaa');
}
}
class Rifle extends AbstractGun {
public shoot() {
console.log('bbb');
}
}
class CachineGun extends AbstractGun {
public shoot() {
console.log('ccc');
}
}
class Soldier {
private gun: AbstractGun;
public getGun(gun: AbstractGun) {
this.gun = gun;
}
public killEnemy() {
console.log(this.gun.shoot());
}
}
四.依赖倒置原则
依赖倒转原则(Dependency Inversion Principle, DIP):抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。
依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。
例子
interface ICar {
run(): void;
}
class Benz implements ICar {
public run() {
console.log('benz');
}
}
class BWM implements ICar {
public run() {
console.log('BWM');
}
}
interface IDriver {
drive(car: ICar): void;
}
class Driver implements IDriver{
drive(car: ICar) {
car.run();
}
}
class Boss {
public goOut() {
let myDriver = new Driver();
let myOldCar = new Benz();
let myNewCar = new BWM();
myDriver.drive(myOldCar);
myDriver.drive(myNewCar);
}
}
五.接口隔离原则
接口隔离原则(Interface Segregation Principle, ISP):使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干。
接口仅仅提供客户端需要的行为,客户端不需要的行为则隐藏起来,应当为客户端提供尽可能小的单独的接口,而不要提供大的总接口。
在使用接口隔离原则时,我们需要注意控制接口的粒度,接口不能太小,如果太小会导致系统中接口泛滥,不利于维护;接口也不能太大,太大的接口将违背接口隔离原则,灵活性较差,使用起来很不方便。
六.迪米特法则
迪米特法则(Law of Demeter, LoD):一个软件实体应当尽可能少地与其他实体发生相互作用。
当前对象本身(this)、以参数形式传入到当前对象方法中的对象、当前对象的成员对象、如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友、当前对象所创建的对象。
应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。
在类的划分上,应当尽量创建松耦合的类,类之间的耦合度越低,就越有利于复用,一个处在松耦合中的类一旦被修改,不会对关联的类造成太大波及;在类的结构设计上,每一个类都应当尽量降低其成员变量和成员函数的访问权限;在类的设计上,只要有可能,一个类型应当设计成不变类;在对其他类的引用上,一个对象对其他对象的引用应当降到最低。
ps: 设计模式的核心思想就是封装变化,隔离变化。