设计模式(通俗言语)
面向对象设计有以下几种原则
1.开闭原则 Open-Close Principle(OCP)
2.里氏替换原则 Liskov Substitution Principle(LSP)
3.单一职责原则 Single Responsibility Principle(SRP)
4.接口隔离原则 Interface Segregation Principle(ISP)
5.依赖倒置原则 Dependence Inversion Principle(DIP)
6.迪米特原则/最少知识原则 Law of Demeter or Least Knowledge Principle(LOD orLKP)
7.组合/聚合复用原则 Composition/Aggregation Reuse Principle(CARP)
概述
1.开闭原则: 含义:对扩展开放,对修改关闭。
我们写的代码,不能因为需求变化了就要修改原有代码,我们可以通过新增代码的方式来解决变化的需求。在现实中,我们要尽量缩小这种修改。
意义:如果每次需求变动都要去修改既有代码,那原有的代码就存在修改错误的风险,当然这其中存在有意和无意的修改,都会导致原有正常运行的功能失效的风险,这样很有可能引起蝴蝶效应,使维护工作剧增。
潜台词:控制需求变动风险,缩小维护成本。
其他的原则都是为此原则服务的。
2.里氏替换原则: 含义:子类可以在任何地方替换它的父类。
这是多态的前提,我们后面许多所谓的灵活,都是不改变声明类型的情况下,改变实例化类来完成的需求变更。
潜台词:尽量使用精准的抽象类或者接口。
3.单一职责原则: 含义:类的职责单一,引起类变化的原因单一。
灵活的前提,将类拆分成最小的职能单位,那组合与复用就简单的多,如果一个类做的事情太多,在组合的时候,就会产生不必要的方法,这是一种污染。
潜台词:拆分到最小单位,解决复用和组合问题。
4.接口隔离原则: 含义:尽量使用职能单一的接口,而不使用职能复杂、全面的接口。
它是单一职责的必要手段,如果子类想达到职能单一,那么接口也必须满足职能单一。相反,如果接口融合了多个不相关的方法,那它的子类就要被迫实现所有方法,尽管有些方法是根本用不到的,这就是接口污染。
潜台词:拆分,从接口开始。
5.依赖倒置原则: 含义:要求调用者和被调用者都依赖抽象。
面向对象初期的程序,被调用者依赖于调用者,也就是调用者决定被调用者有什么方法,有什么实现方式,这种结构在需求变更的时候,会付出很大的代价,甚至推翻重写。依赖倒置原则要求调用者和被调用者都依赖抽象,线河阳两者没有直接的关联和接触,在变动的时候,一方的变动不会影响另一方的变动。
潜台词:面向抽象编程,解耦调用和被调用者。
6.迪米特原则: 含义:要求尽量的封装,尽量的独立,尽量的使用低级别的访问修饰符。
一个类如果暴露太多私用的方法和字段,会让调用者很迷茫。并且会给类造成不必要的判断代码。所以,我们使用尽量低的访问修饰符,让外界不知道我们的内部,这也是面向对象的基本思路。这是迪米特原则的一个特性,无法了解类更多的私有信息。另外,迪米特原则要求类之间的直接联系尽量的少,两个类的访问,通过第三个中介类来实现。
潜台词:不和陌生人说话,有事去中介。
7.组合/聚合复用原则: 含义:如果只是达到代码复用的目的,尽量使用组合与聚合,而不是继承。
继承的耦合性更大,比如一个父类后来添加实现一个接口或者去掉一个接口,那子类可能会遭到毁灭性的编译错误,但如果只是组合聚合,只是引用类的方法,就不会有这种巨大的风险,同时也实现了复用。
潜台词:我只是用你的方法,我们不一定是同类。
注意点:
1.高内聚、低耦合和单一职能的“冲突”
实际上,两者是同一回事。内聚,要求一个类把所有相关的方法放在一起,初看是职能多,但有个“高”,就是要求把联系非常紧密的功能放在一起,也就是说,从整体看,是一个职能的才放在一起,所以,两者是不同的表述而已。
2.多个单一职能接口的灵活性和声明类型问题
如果一个类实现多个接口,那么这个类应该用哪个接口类型声明呢?应该是用一个抽象类来继承多个接口,而实现类来继承这个抽象类,声明的时候,类型是抽象类。
3.最少知识原则和中介类泛滥两种极端情况
迪米特原则要求类中间要用中介来通信,但类多了以后,会造成中介类泛滥的情况,这种情况,我们可以考虑中介模式,用一个总的中介类来实现。当然,设计模式都有自己的缺陷,迪米特原则也不是十全十美,交互类非常繁多的情况下,要适当的牺牲设计原则。
4.继承和组合聚合复用原则的冲突
继承也能实现复用,那这个原则是不是要抛弃继承了?不是的。继承更注重的是“血统”,也就是什么类型的,而组合聚合更注重的是借用“技能”。并且,组合聚合中,两个类是部分与整体的关系,组合聚合可以由多个类的技能组成。在C#和Java中只有单继承。这个原则告诉我们,在复用这点上,优先使用组合聚合。
共性问题
1.这么多设计模式,都要学习和使用么?
我们只是掌握总体的原则,然后学习常用的就行了。实际开发中也不是每种设计模式都会经常用到。因为归根结底,设计模式也好,架构也好,都是为需求服务的,没有需求业务模型,不能生搬硬套模式,我们在学习时,多学一些总是好的,但只是为了开阔自己的眼界。
2.设计模式是规范么?是不是好的程序必须使用设计模式?
严格来说,好的程序遵循的是设计原则,而非设计模式。现在就出现很多新的演变出来的模式,这些都是因为出现了新业务的原因,设计模式不是规范,只是一种借鉴。
3.使用设计模式会不会增加开发难度?
开发阶段会的,而且会延长开发时间。但一个项目或产品从开始到结束,开发只是其中很小的一部分,考虑到维护和扩展成本,才会出现设计模式。从整体考虑,设计模式是减少了开发时间和成本的。