架构师训练营,第二周总结
一、软件设计的“臭味”
软件设计的最终目的,是使软件达到“强内聚、松耦合”,从而使软件:
易扩展- 易于增加新的功能
更强壮- 不容易被粗心的程序员破坏
可移植- 能够在多样的环境下运行
更简单- 容易理解、容易维护
”臭味”:
僵硬- 不易改变。
脆弱- 只想改A,结果B 被意外破坏。
不可移植- 不能适应环境的变化。
导致误用的陷阱- 做错误的事比做正确的事更容易,引诱程序员破坏原有的设计。
晦涩- 代码难以理解。
过度设计、copy-paste 代码。
二、OOD 原则
2.1 开/闭原则(OCP)
对于扩展是开放的(Open for extension)
对于更改是封闭的(Closed for modification)
简言之:不需要修改软件实体(类、模块、函数等),就应该能实现功能的扩展。
当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
2.2依赖倒置原则(DIP)
高层模块不能依赖低层模块,而是大家都依赖于抽象;
抽象不能依赖实现,而是实现依赖抽象。
如果高层依赖于低层,当低层发生变动的时候,高层也要随之改动,导致模块的复用性大大降低,增加开发的成本.实现依赖于抽象,当需求发生了微小的变动,我们只需要修改对应的实现,只要抽象不变,框架就不太会发生变化;
2.3Liskov替换原则(LSP)
若对每个类型T1 的对象o1,都存在一个类型T2 的对象o2,使得在所有针对T2 编写的程
序P 中,用o1 替换o2 后,程序P 的行为功能不变,则T1 是T2 的子类型。
简言之:子类型(subtype)必须能够替换掉它们的基类型(base type)。
1、里氏替换原则是针对继承而言的,如果继承是为了实现代码重用,也就是为了共享方法,那么共享的父类方法就应该保持不变,不能被子类重新定义。子类只能通过新添加方法来扩展功能,父类和子类都可以实例化,而子类继承的方法和父类是一样的,父类调用方法的地方,子类也可以调用同一个继承得来的,逻辑和父类一致的方法,这时用子类对象将父类对象替换掉时,当然逻辑一致,相安无事。
2、如果继承的目的是为了多态,而多态的前提就是子类覆盖并重新定义父类的方法,为了符合LSP,我们应该将父类定义为抽象类,并定义抽象方法,让子类重新定义这些方法,当父类是抽象类时,父类就是不能实例化,所以也不存在可实例化的父类对象在程序里。也就不存在子类替换父类实例(根本不存在父类实例了)时逻辑不一致的可能。
2.4单一职责原则(SRP)
又被称为“内聚性原则(Cohesion)”,意为:一个模块的组成元素之间的功能相关性。
将它与引起一个模块改变的作用力相联,就形成了如下描述:一个类,只能有一个引起它的变化的原 因。
假如有A和B两个类,当A需求发生改变需要修改时,不能导致B类出问题;优点:降低类的功能复杂度、提高系统的可维护性、变更风险低
2.5接口分离原则(ISP)
不应该强迫客户程序依赖它们不需要的方法。
不要在一个接口里面放很多的方法,这样会显得这个类很臃肿。接口应该尽量细化,一个接口对应一个功能模块,同时接口里面的方法应该尽可能的少,使接口更加灵活轻便。
接口隔离原则和单一职责原则区别:
单一职责原则是在业务逻辑上的划分,注重的是职责。接口隔离原则是基于接口设计考虑。例如一个接口的职责包含10个方法,这10个方法都放在同一接口中,并且提供给多个模块调用,但不同模块需要依赖的方法是不一样的,这时模块为了实现自己的功能就不得不实现一些对其没有意义的方法,这样的设计是不符合接口隔离原则的。接口隔离原则要求"尽量使用多个专门的接口"专门提供给不同的模块。
评论