目录
一、开闭原则 OCP(Open-Close Principle)
二、依赖倒转原则DIP(Dependence Inversion Principle)
三、合成聚合复用原则CARP composite /aggregate reuse principle
四、接口隔离原则 Interface Segregation Principle
五、里氏代换原则 Liskov Substitution Principle
六、迪米特法则 Law of Demeter
图片来源:Java programmer says: No problem, I can use these seven design patterns for that. - Baby Businessman - quickmeme
在软件工程中,设计模式(design pattern)是对软件设计中普遍存在的各种问题提出的解决思路和方案。无数软件开发人员经过长时间的实践总结出来这些经验和基本方法。一起从生活中发现设计模式,包括学校的不同教师、子女教育、人的各种角色、分工协作、开汽车、朋友圈、系统设计、人的独立性等等,学习和运用设计模式的原则。
一个软件实体应当对扩展开放,对修改关闭。Software entities should be open or extension, but closed for modification.通过扩展已有的软件系统,可以提供新的行为,以满足对软件的新需求,使变化中的软件系统由一定的适应性和灵活性。
已有的软件模块,特别是最重要的抽象层模块不可被修改,使变化中的软件系统有一定的稳定性和延续性。一个系统不可扩展,就会失去使用的价值,一个系统总是需要修改,就会失去重心。具体来说,不兴师动众,不破坏既有规则也就是重要的抽象层叫做“闭”,做必要的扩展满足新的功能就叫“开”。
这种设计思想可以用到很多系统的构建中,例如经济的,教育的,个人价值观,或者自己新家的装修中。图中例子说明,在一个学校里,增加心理辅导老师,不改变学习既有的规则,同时针对学生变化的情况增加心理辅导老师这个新角色。
图片来源:笔者绘制
抽象不应当依赖于细节,细节应当依赖于抽象。Abstractions should not depend upon details. Details should depend upon abstractions. or Program to an interface, not an implementation.
抽象可以说是系统的战略性决定,在家庭生活中,比如对子女的教育来说是一些宏观的教育理念,而细节是战术实施,就是子女教育过程中的具体实施细节。每个战术不应该偏离基本的战略,或者说是一个原则。解释一下,抽象不应当依赖于细节,也就是说战略决策(教育理念)决定战术实施(具体的教育方法和方式)。这个道理很简单,但是由于过去传统的面向过程的设计中倾向于使高层次的模块依赖于低层次的模块,所以在面向对象的设计中,有些人会基于同样的思想来做设计,就会导致依赖错误。
图片来源:笔者绘制
尽量使用合成/聚合,尽量不要使用继承。
composite /aggregate 也即Has-A,即某个角色具有某一项责任。比如CEO担负着公司管理和发展的重大责任。继承,Is-A是说明一个类是另一个类的一种。我们做为人,有CEO的角色,有做为子女的角色,有做为父母的角色。如果使用继承来实现角色,我们每个人具有Has-A角色,因为继承是静态的,当我们成为CEO以后,就不能再称为“子女”或者“父母”,所以我们不能用继承描述关系。如下图,当我们正确区分了“人”与不同角色的差异后,就能做出正确的设计。记住自己角色的变化,工作和生活才会各有所得。回到家中,忘记公司的CXO角色,摆脱管理者的姿态,好好做子女,好好做父母和兄长姐妹,生活就会美好很多吧。
图片来源:笔者绘制
使用多个专门的接口比使用单一的总接口要好。也就是说,一个类对另一个类的依赖性应当是建立在最小的接口上。具体来说,就是专人做专事,讲究分工协作,比如制造业里每个人专注于自己的职责,比如餐饮业里很细的分工。万万不可一个人做很多的事情,角色和职责不明。
前面我们谈到了“开闭”原则,开闭原则强调了面向对象设计的基本原则,也就是创建抽象化,并且从抽象化导出具体化。利用继承关系和里氏代换原则,就可以实现从抽象化到具体化的过程了。这里的代换是指衍生类可以替换掉基类,也就是说,衍生类具备基类的所有特性。用生活中的例子来说呢,如下图所示,人可以开汽车(基类),保时捷也好,奇瑞也好,都是汽车的一种,也就是汽车的具体衍生类,既然汽车可以被人驾驶,那么保时捷和奇瑞都可以被人驾驶。
也叫最少知识原则(Least Knowledge Principle ),是面向对象设计的一种法则,可以理解为弱耦合。包括以下基本定义
1.只与直接的朋友们交流
2.不和陌生人说话
3.每一个软件模块对其他的模块只有最少的知识
直接的朋友是指存在耦合关系的朋友,耦合的方式很多,包括依赖、关联、组合、聚合等。陌生人就是指没有耦合关系的人。
用微信的朋友圈来类比这个概念,就很容易理解了。微信的社交只局限在朋友之间,陌生人和被拉黑的人是不可能了解到我们的信息的。迪米特法则其实就是在控制对象之间的信息流量、流向以及信息所带来的影响,也就是控制信息过载。笔者曾经写过用推荐系统来控制信息超载。
图片来源:Information Overload Day - October 20, 2021 - Happy Days 365
很明显,如果我们遵循以上的原则,我们会发现,一个系统的局部设计简单了,但是,由于系统里会生成大量的小方法,这样会降低系统的不同模块之间的通信效率,也会增加系统的不同模块之间协调的难度。所以在系统设计的时候,我们要平衡弱耦合和结构清晰,既能保证系统结构清晰,又能做到低耦合。
图片来源: Coupling in Java - GeeksforGeeks
做到低耦合,更多地隐藏自己的内部信息和实现细节,也就是封装。到生活中怎么说呢,我们不依赖于他人而存在,我们每个人就有很大的价值,可以独立地在任何地方看到自己的价值。同时,当我们发现自己的缺陷时,我们修正自己,也不会影响到他人。