在程序设计畛域,罗伯特·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
总结
- 繁多职责:实现类须要职责繁多。
- 里氏替换准则:不要毁坏继承体系。
- 接口隔离准则:设计的接口要精简。
- 依赖倒置准则:面向接口编程。
- 【总纲】凋谢关闭准则:对扩大凋谢,对批改敞开。
人无完人,金无足赤。实践结合实际,不要刻意追求完满,而是要在适当的场景遵循适当的设计准则,体现出一种均衡的取舍。帮忙咱们设计出更加优雅的代码构造。