面向对象设计原则简介
设计原则就是架构设计的指导思想,它指导我们如何将数据和函数组织成类,如何将类链接起来成为组件和程序。反向来说,架构的主要工作就是将软件拆解成组件,设计原则指导我们如何拆解。拆解的粒度、组件间的依赖方向、组件解耦的方式等。
面向对象设计原则有很多,我们进行架构设计的主导原则是开闭原则(OCP)。
在类和代码的层级伤有:
单一职责原则 SRP
里氏替换原则 LSP
接口隔离原则 ISP
依赖反转原则
在组件层级上有:
复用、发布等原则
共同闭包原则
共同复用原则
处理组件依赖问题的三原则:无依赖原则、稳定依赖原则、稳定抽象原则。
设计原则
开闭原则(Open-Closed Principle, OCP)
设计好的软件应该易于扩展,同时抗拒修改。这里我们进行架构设计的主导原则。其他的原则都为这条原则服务。
一个软件实体应对扩展开放,对修改关闭
在设计一个模块时应当使这个模块可以在不被修改的情况下被扩展,即实现在不被修改源代码的情况下改变这个模块的行为。
为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。在面向对象变成语言中,可以为系统定义一个相对稳定的抽象层,而将不同的实现行为在具体的实现层中完成。如果要修改系统的行为,无需对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,实现在不修改已有代码的基础上扩展系统的功能,达到开闭原则的要求。
开闭原则还可以通过一个更具体的“对可变性封装原则”来描述,对可变性封装原则(Principle of Encapsulation of Variation, EVP)要求找到系统的可变性因素并将其封装起来。如将抽象层的不同实现封装到不同具体类中,而且EVP要求尽量不要将一种可变性和另一种可变性混合在一起,这将导致系统中的类的个数急剧增长,增加系统的复杂度。
以上部分摘自:https://blog.csdn.net/weixin_40216444/article/details/88120877
单一职责原则(Single responsibility principle SRP)
任何一个软件模块,都应该有且只有一个被修改的原因,“被修改原因”指系统的用户或所有者,说人话就是,任何模块只对一个用户的价值负责,该原则指定我们如何拆分组件。
不要存在多于一个导致类变更的原因
一个类、接口或方法只负责一项职责或职能
优点:
降低类的复杂度;
提高类的可读性,因为类的职能单一,看起来比较有目的性,显的简单;
提高系统的可维护性,降低变更程序引起的风险。
缺点是如果一味追求单一职责,会导致类的数量非常多,你会发现,可以无限拆分下去。
上面摘自:https://blog.csdn.net/qq_24990561/article/details/87398385
上面网址中的例子,涉及到了其他的设计模式,我不举例子了,大概意思就是一个类,最好只有一个功能或者一类功能。
里氏替换原则 (Liskov substitution principle LSP)
当用统一接口的不同实现互相替换时,系统的行为应该保持不变,该原则指导的是接口与其实现方式。
我现在理解不透的就是这个原则,感觉很模糊,没有一个清晰的认识。
所有引用基类(父类)的地方必须能透明的使用其子类对象。
通俗的说就是,在软件中将一个基类对象替换成它的子类对象,程序不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。例如:我喜欢动物,那我一定喜欢狗,因为狗是动物的子类;但是我喜欢狗,不能据此判定我喜欢动物,因为我可能不喜欢老鼠,虽然它是动物。
使用时注意:
子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法(比如PHP中接口)。根据里氏替换原则,为了曹正系统的扩展性,在程序中通常使用父类来进行定义。如果一个方法只存在子类中,在父类中不提供相应声明,则无法在以父类行的对象中使用该方法。
我们在运用里氏替换原则时,尽量把父类设计为抽象类或者接口,让子类继承或者实现它,并实现其定义的方法,运行时,子类实例替换父类实例,我们可以很方便地扩展系统的功能,同时无需修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现。里氏替换原则是开闭原则的具体实现手段之一。
上面摘自:https://www.cnblogs.com/cxks-xu/p/8554488.html
这里我理解出现了偏差,我把它和自动注入混在一起理解了。
接口隔离原则(Interface Segregation Principle)
不依赖不需要的方法、类或组件。该原则指导我们的接口设计。当我们依赖一个接口但只用到了其中的部分方法时,其实我们已经依赖了不需要的方法或者类。当这些方法或者类有变更时,会引起我们类的重新编译,或者引起我们组件的重新部署,这些都是不必要的。所以我们最好定义个小接口,把用到的方法拆出来。
我是PHP 这个说的很像
trait
,使用它可以很好的拆分类的方法。
----------- 未完待续----------
2019年10月18日
-------------续上-------------
2019年10月23日
依赖反转原则(Dependence Inversion Principle DIP)
依赖反转原则指一种特定的解耦(传统的依赖关系创建在高层次伤,而具体的策略设置则应用在低层次的模块上)形式,使得高层次的模块不依赖于低层次的模块的而实现细节,依赖关系被颠倒(倒置),从而使得低层次的模块的需求抽象。
跨越组建边界的依赖方向永远与控制流的方向相反,该原则知道我们设计组件间的依赖方向。
依赖反转原则是个可操作性非常强的原则,当你要修改组建的依赖方向时,将需要将进行组件间通信的类抽象为借口,接口放置在边界的那里,依赖就指向哪边。
复用、发布等同原则(Release Reuse Equivalency Principle REP)
软件复用的最小粒度应等同于其发布的最小粒度。直白地说,就是要复用一段代码就把他抽象成组件,这个原则,告诉我们怎么拆分组件及其粒度。
共同闭包原则(Common Closure Principle CCP)
为了相同的目的而同时修改的类,应该放在同一组件中。CCP原则是SRP()在组件层面的描述。我们可以根据这个原则来决定我们拆分组件的粒度。
对于大部分应用程序而言,可维护性的重要性远远大于可复用性,由同一原因引起的代码修改,最好在同一个组件中,如果分散在多个组件中,那么开发、提交、部署的成本都回上升。
共同复用原则(Common Reuse Principle CRP)
不要强迫一个组件依赖它不需要的东西。SRP原则是ISP原则在组件层面的描述。改原则指导我们组件的拆分的粒度。
相信你移动有这种经历,继承了组件A,但组件A依赖了组件B,C。即使组件B,C你完全用不到,也不得不集成进来。这时因为你只用到了组件A的部分能力,组件A中额外的能力带来了额外的依赖。如果遵循共同复用原则,你需要把A拆分,只保留要的部分。
一些总结
REP、CCP、CEP、三个原则之间存在彼此竞争关系,REP和CCP是粘合性原则,他们会让组件变的更大,而CRP原则是排除原则,它会让组件变小,遵守REP、CCP而忽略CRP,就会依赖了太多没有用到的组件和类,而这些组件或类的变动会导致你自己的组件进行太多不必要的发布;遵守REP、CRP而忽略CCP,会因为组件拆分太细了,一个需求变更可能要改n个组件,带来的成本也是巨大的。
抄录一遍对自己有不小的提升,虽然自己也知道一些原则,但是没有一个明确的定义,导致别人问的时候,按照自己的理解解释,而不会说一些名词,导致逼格的降低(....)。
评论已关闭