在程序设计畛域,罗伯特·C·马丁指出了 面向对象编程
和面对对象设计
的五大根本准则:SOLID。开发一个零碎时,如果利用这些准则,将会让零碎变得更加易于保护和扩大。
SOLID 是由五个设计准则的首字母组成的:
- S – 繁多职责准则 – Single Responsibility Principle
- O – 凋谢关闭准则 – Open Close Principle
- L – 里氏替换准则 – Liskov Substitution Principle
- I – 接口拆散准则 – Interface Segregation Principle
- D – 依赖倒置准则 – Dependency Inversion Principle
上面就 SOLID 五大设计准则,一起来看看。
S:繁多职责准则(Single Responsibility Principle)
一个类(模块、函数等),只有一个职责;将多职责的类拆分为多个类,放弃各个类的互相独立。
益处:进步代码的可读性和可维护性,升高代码的复杂度,缩小批改代码的影响范畴。
任何代码都有可能批改。如果在一个类中实现多个不相干的职责,那么在批改其中一个职责的相干代码时,很有可能影响到其余职责的相干代码,造成这个类的不稳固影响范畴变大。
因而须要将多职责的类拆分为单职责的类,即便某一个职责相干代码须要批改,其影响范畴仅限于这个类,其余职责的代码不受这个职责代码批改的影响。
例如:
// 一个光猫类,有两个职责:一个是治理连贯(dial 和 hangup);一个是数据传输(send 和 receive)class Model {dial (pno: string) {}
hangup () {}
send (msg: string) {}
receive(data: string) {}}
// 通常这两个职责并没有共同点,在一个类中实现,过于耦合。应该将其离开到两个绝对独立的类中,别离保护。class Connection {dial (pno: string) {}
hangup () {}
}
class DataChannel {send (msg: string) {}
receive(data: string) {}}
class Model {constructor () {const connection = new Connection()
const dataChannel = new DataChannel()}
}
O:凋谢关闭准则(Open Close Principle)
当增加一个新的性能时,应该在已有代码的根底上扩大代码(新增模块、类、函数等),而不是批改已有的代码(批改模块、类、函数等)。
益处:进步代码的稳定性和灵活性。
例如:
// 有两种电脑:苹果电脑和华硕电脑。这两种电脑都继承 Computer 类。class Computer {getPrice() {}}
class MacComputer extends Computer {}
class AsusComputer extends Computer {}
// 当双十一打折促销时,须要对电脑实现提价销售。此时不应该批改类的代码,而是应该扩大一个打折类。class AsusDiscountComputer extends AsusComputer {getDiscountPrice() {}}
// 当双十一购物节过来后,AsusDiscountComputer 类不再须要时,间接删除即可。
L:里氏替换准则(Liskov Substitution Principle)
子类能够 齐全
替换父类;父类能呈现的中央,子类也能够呈现。
例如:
// 创立一个 Bird 类,假如所有的鸟都会飞
class Bird{fly() {}}
const allFly = (birds) => birds.forEach(bird => bird.fly())
allFly([new Bird(), new Bird(), new Bird()])
// 扩大三个子类:鸭子、鹦鹉、天鹅
class Duck extends Bird {quack(){}}
class Parrot extends Bird {repeat(){}}
class Swan extends Bird{beBeautiful(){}}
allFly([new Duck(), new Parrot(), new Swan()])
// 再增加一只企鹅,然而企鹅并不会飞,如果想调用 fly 办法,咱们就抛出一个谬误
class Penguin extends Bird {fly(){throw new Error('Sorry, but I cannot fly')
}
swim(){}
}
allFly([new Duck(), new Parrot(), new Swan(), new Penguin()]) // Error: Sorry, but I cannot fly.
// fly 办法并不冀望呈现外部谬误,allFly 办法也只是为会飞的鸟创立的。企鹅不会飞,所以咱们违反了里氏替换准则
// 会飞的鸟与不会飞的鸟不能继承同一个 Bird 类。须要创立一个 FlyingBird 类供会飞的鸟继承
class Bird{
}
class FlyingBird{fly(){}}
class Duck extends FlyingBird {quack(){}}
class Parrot extends FlyingBird {repeat(){}}
class Swan extends FlyingBird{beBeautiful(){}}
class Penguin extends Bird {swim(){}}
I:接口拆散准则(Interface Segregation Principle)
客户端不应该依赖他们不应用的接口(接口应该是精简的,领有尽可能少的行为)。
例如:
// 有一个名为 Troll 的类,它实现了一个名为 Character 的接口,然而 Troll 既不会游泳也不会谈话,所以它仿佛不太适宜实现咱们的接口。interface Character {shoot(): void;
swim(): void;
talk(): void;
dance(): void;}
class Troll implements Character {shoot(): void {// some method}
swim(): void {// a troll can't swim}
talk(): void {// a troll can't talk}
dance(): void {// some method}
}
// 遵循接口隔离准则,删除 Character 接口并将它的性能拆分为四个接口,而后 Troll 类只须要依赖于理论须要的这些接口。interface Talker {talk(): void;
}
interface Shooter {shoot(): void;
}
interface Swimmer {swim(): void;
}
interface Dancer {dance(): void;
}
class Troll implements Shooter, Dancer {shoot(): void {// some method}
dance(): void {// some method}
}
D:依赖倒置准则(Dependency Inversion Principle)
根本定义是:
- 高层模块不应该依赖低层模块,应该独特依赖形象。
- 形象不应该依赖细节,细节应该依赖形象。
这里的形象就是接口和抽象类,而细节就是实现接口或继承抽象类而产生的类。
// 比方宝马 BMW 类、飞驰 Benz 类都有一个 drive 办法,而后 Driver 类通过依赖倒置的形式去实现开不同的车。// 形象
interface ICar {
brand: string
drive(): void}
interface IDriver {setCar(car: ICar): void
drive(car: ICar): void
}
// 细节
class Driver implements IDriver {
private car: ICar
constructor (car: ICar) {this.car = car}
setCar (car: ICar) {this.car = car}
drive () {this.car.drive()
}
}
class BMW implements ICar {
brand: string;
constructor (brand: string) {this.brand = brand}
drive () {}
}
class Benz implements ICar {
brand: string;
constructor (brand: string) {this.brand = brand}
drive () {}
}
const li740 = new BMW('BMW')
const s600 = new Benz('Benz')
const driver = new Driver(li740)
driver.setCar(s600) // replace li740 with s600
总结
- 繁多职责:实现类须要职责繁多。
- 里氏替换准则:不要毁坏继承体系。
- 接口隔离准则:设计的接口要精简。
- 依赖倒置准则:面向接口编程。
- 【总纲】凋谢关闭准则:对扩大凋谢,对批改敞开。
人无完人,金无足赤。实践结合实际,不要刻意追求完满,而是要在适当的场景遵循适当的设计准则,体现出一种均衡的取舍。帮忙咱们设计出更加优雅的代码构造。