java中的设计模式及其六大原则
设计模式分类:
一共分为3大类:创造型模式、结构型模式、行为型模式。
创造型模式:工厂方法(FactoryMethod)、抽象工厂模式(AbstractFactory)、建造者模式(Builder)、单例模式(singleton)、原型模式(prototype)。
结构型模式:适配器模式(adapter)、桥接模式(Bridge)、组合模式(Composite)、装饰者模式(Decorator)、外观模式(Facede)、享元模式(Flyweight)、代理模式(Proxy)
行为模式:责任链模式(Chain of Responsibility)、命令模式(Command)、解释器模式(Interpreter)、迭代器模式(Iterator)、中介者模式(Mediator)、备忘录模式(Memento)、
观察者模式(Observer)、状态模式(State)、策略模式(Strategy)、模板方法模式(TemplateMethod)、访问者模式(Visitor)。
单一职责原则:
定义:不要存在多于一个导致类变更的原因。
通俗地说:一个类只负责一项职责。
问题来源:一个类T负责两个职责:职责1和职责2,当因为职责1因需求变化时,可能会导致职责2的功能发生故障。
解决方案:遵循单一职责原则,分别建立两个类:T1负责职责1,T2负责职责2。这样当因需求修改类时就不会导致别的功能出现异常。
看似简单但实际上因为开发时间的不同,或者是业务需求的变化可能会导致本来符合单一职责原则的类变得不符合这一原则。
所以涉及到开发或模块涉及时尽量将业务逻辑简单化,细分化。这样出现问题的时候,在做添加的时候,可以避免耦合过高影响其他功能的情况出现。
优点:
- 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;
- 提高类的可读性,提高系统的可维护性;
- 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。
需要说明的一点是单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。
里氏替换原则:
定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。
(这个定义,我表示。。。。。。。。)
定义2:所有引用基类的地方必须能透明地使用其子类的对象。
定义3:子类型必须能够替换掉它们的父类型。
大众点的感觉:子类可以扩展父类的功能,但是不能改变父类的功能。(如果改变了父类的功能,会导致子类无法替换父类,导致引用出现异常)。
个人理解的话,更像是因为假如子类篡改了父类的功能,会导致在多态的时候父类无法成功地指向子类最终引起程序的功能瘫痪。
里氏替换原则是开闭原则的补充,实现开闭原则的关键就是抽象化,而基类与子类的继承关系就是抽象化的具体体现。里氏原则是对实现抽象化的具体规范。
在进行设计时,我们应该尽量从抽象类继承,而不是从具体类继承。如果从继承树上来看,所有的叶子节点都应该是具体类,而所有的树枝节点应该是抽象类或者接口。
感觉里氏替换原则在框架中非常常见,看过Spring的一点源码跟源码解析,其中Spring容器的继承树就非常符合里氏替换原则(当然也很符合其他的设计原则,比如单一功能原则之类的)。
依赖倒置原则:
定义:高层模块不应该依赖低层模块。两个都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象;(针对接口编程,而不是针对实现;)
我感觉这个好像没什么需要太分析的吧?
抽象(接口)应该是一切模块的依赖起源。具体的实现(细节),应该依赖于接口(抽象)而存在。
通过抽象来规范业务方向,然后通过细节来实现抽象,当实际需求发生变化的时候,可以直接修改细节来实现而不需要对抽象进行修改(当然你的抽象得考虑周全,不过也可以利用接口的多实现来弥补这个问题。果然规则制定者是最厉害的啊)。
接口隔离原则/合成聚合原则:
定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
个人感觉这就像是避免出现规模庞大的接口,可以将复杂的功能分散到多个接口中,最终通过多实现了灵活性与复用性。
(假如你们源接口功能庞大,你要实现的功能位于其中,但是你只是想实现其部分功能,那多余的功能对于你来说是不是像鸡肋一样,不可不实现,但是实现了也是空白。食之无味,弃之可惜啊)
注意情况:
- 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
- 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
- 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
感觉这些设计模式的原则,不仅仅是对设计模式有用,实际对于项目的开发也很有用,如果项目开发时能遵循这些原则,那么后续维护和升级就会相对简单很多。或者说代码的可读性什么的都能得到很好的继承和维护。但是一旦你设计出了问题,在后续的开发过程中可能需要你用别的方法来解决,最终导致出现莫名其妙的bug,导致后期维护难度增大。
果然应该多看多想,形成思路之后再往后走。
迪米特法则:
定义1:一个对象应该对其他对象保持最少的了解。
定义2:如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用,如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
核心思想是:类之间的松耦合(不管对于什么项目来说,你中有我我中有你都不是一个很好的现象。也是这几个原则看到现在的感受,无时无刻不在提示,不要造成相互纠缠,或者说降低耦合性)。
实质是尽量避免出现类作为成员变量存在。(感觉这样又有点跟面向接口编程有冲突,不过应该不算冲突的意思吧。反正目前在我看来是有点这么个意思)。
开闭原则:
定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
这样做,面对需求变化,通过扩展来实现新需求,可以使整个程序从第一个版本开始就有很好的功能性(第一版设计完成实现之后就能满足其业务需要)跟拓展性(面对新需求新需要,可以通过拓展功能来实现。)
(但是根据上面括号的内容想来,程序的体谅会越来越大越来越难以维护,就目前看我感觉这是所有程序的最终宿命)。
上述就是六大原则跟我对这些原则的理解。鉴于学习过程的局限性,或者说知识体系的局限性,可能还有很多问题。如果有朋友看到可以放心大胆地指出。
我很欢迎批评,也很乐于接受批评,也很愿意跟各位在交流中相互学习。
期待你的到来