设计模式原则总结

单一职责原则

定义不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
问题由来:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。

解决方案:遵循单一职责原则。分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使职责P1发生故障风险。在这里插入图片描述
比如图中的setPassword和changePassword,两个原因都会引起类的变化。导致的问题就是出现问题不知道去哪里排查。如果遵循单一职责原则,就很明确在哪里调用了改变的方法即可。定位很明确。所以可以将changepassword跟setpassword分成两个类,changgepassword方法去调用setpasswprd。

接口隔离原则

“客户端不应该依赖它不需要的接口”,这里的隔离是指客户端和它不需要的接口隔离,也就是客户端不要使用它不需要的接口,这个很容易理解,在实践中也很容易实现。
“类间的依赖关系应该建立在最小的接口上”,它要求“最小的接口”,也就是该接口中没有多余的方法,所以这里的隔离是指和多余的方法隔离。
尤其在需求细化以后,会伴随着接口隔离的问题发生。比如“美女”的定义。之前对于美女的定义就是漂亮脸蛋,长挑身材,出众气质。这些特点可以用同一接口定义。让实现类去实现。可是后来人们发现美女分两类漂亮脸蛋,长挑身材出众气质。所以他们是可以分类的,如果还像之前一样的划分显然不够灵活,造成接口污染。所以就可以将之前的接口分为两部分,让实现类分别实现。更好的情况是java可以多实现。这样就实现了接口的最小化,避免类中有空实现的方法为之后留下隐患。然而细化以后造成的问题就会有代码复用性差。由于不是同一个接口,依赖倒置的问题又会失效。接口隔离和单一职责原则有紧密联系在一起。所以需要掌握一个度。根据实际项目出发。

依赖倒置

依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合。我们在项目中使用这个原则要遵循下面的规则:

  • 每个类尽量都有接口或者抽象类,或者抽象类和接口两都具备
    变量的表面类型尽量是接口或者抽象类
  • 任何类都不应该从具体类派生
  • 尽量不要覆写基类的方法
  • 如果基类是一个抽象类,而这个方法已经实现了,子类尽量不要覆写。类间依赖的是抽象,覆写了抽象方法,对依赖的稳定性会有一定的影响。
  • 结合里氏替换原则使用
    里氏替换原则:父类出现的地方子类就能出现。结合本章我们得出了一个通俗的规则:接口负责定义public属性和方法,并且声明与其他对象的依赖关系。抽象类负责公共构造部分的实现,实现类准确的实现业务逻辑,同时在适当的时候对父类进行细化。
    主要作用还是降低耦合度,使用抽象类和接口去接受对象。

里氏替换原则

里氏替换原则包含以下4层含义:

  • 子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法。
  • 子类中可以增加自己特有的方法。
  • 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
  • 里氏替换原则的关键点在于不能覆盖父类的非抽象方法。父类中凡是已经实现好的方法,实际上是在设定一系列的规范和契约,
  • 虽然它不强制要求所有的子类必须遵从这些规范,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。
class StudyA {
   public int func1(int a, int b) {
       return a - b;
   }
}

/*
后来,我们需要增加一个新的功能:完成两数相加,然后再与100求和,由类StudyB来负责。即类StudyB需要完成两个功能:
两数相减。
两数相加,然后再加100。
*/

class StudyB extends StudyA {
   public int func1(int a, int b){
       return a+b;
   }

   public int func2(int a, int b){
       return func1(a,b)+100;
   }
}


public class Lishi {
   public static void main(String[] args){
       StudyA a = new StudyA();
       System.out.println("100-50="+a.func1(100, 50));
       System.out.println("100-80="+a.func1(100, 80));
       /*
       运行结果:
       100-50=50
       100-80=20
        */

       StudyB b = new StudyB();
       System.out.println("100-50="+b.func1(100, 50));
       System.out.println("100-80="+b.func1(100, 80));
       System.out.println("100+20+100="+b.func2(100, 20));
       /*
       运行结果:
       100-50=150
       100-80=180
       100+20+100=220
        */
   }
100-50=50
100-80=20
100-50=150
100-80=180
100+20+100=220

从输出结果出看,100-50=150 100-80=180 出现错误结果,就是因为子类失误重写了父类的已经实现好的方法倒导致的。

迪米特法则

迪米特法则(Law of Demeter, LoD)是1987年秋天由lan holland在美国东北大学一个叫做迪米特的项目设计提出的,它要求一个对象应该对其他对象有最少的了解,所以迪米特法则又叫做最少知识原则(Least Knowledge Principle, LKP)。

迪米特法则的意义在于降低类之间的耦合。由于每个对象尽量减少对其他对象的了解,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。

值得一提的是,这一法则却不仅仅局限于计算机领域,在其他领域也同样适用。比如,美国人就在航天系统的设计中采用这一法则。
最形象的说明就是Controller层调用Service层调用Dao层。C层是不知道D层的存在的。通过调用Service层是调用Dao层。这样就可以降低Controller层的耦合度。使C层的代码可读性增强。
迪米特法则的核心观念就是类间解耦,弱耦合。只有弱耦合了之后,类的复用才可以提高,类变更的风险才可以减低。但解耦是有限度的,除非是计算机的最小单元–二进制的0和1,否则都是存在耦合的。所以在实际项目中,需要适度地参考这个原则,避免过犹不及

开闭原则

软件对象(类、模块、方法等)应该对于扩展是开放的,对修改是关闭的。比如:一个网络模块,原来只有服务端功能,而现在要加入客户端功能,那么应当在不用修改服务端功能代码的前提下,就能够增加客户端功能的实现代码,这要求在设计之初,就应当将客户端和服务端分开。公共部分抽象出来。
明白一点的话就是不能修改现有的类代码,实现新功能的话需要创建新的类。但是新创建的类需要跟现有代码有极高的相识度。
开闭原则是面向对象设计中最基础的设计原则,它指导我们如何建立稳定灵活的系统。开闭原则可能是设计模式六项原则中定义最模糊的一个了,它只告诉我们对扩展开放,对修改关闭,可是到底如何才能做到对扩展开放,对修改关闭,并没有明确的告诉我们。以前,如果有人告诉我"你进行设计的时候一定要遵守开闭原则",我会觉的他什么都没说,但貌似又什么都说了。因为开闭原则真的太虚了。

在仔细思考以及仔细阅读很多设计模式的文章后,终于对开闭原则有了一点认识。其实,我们遵循设计模式前面5大原则,以及使用23种设计模式的目的就是遵循开闭原则。也就是说,只要我们对前面5项原则遵守的好了,设计出的软件自然是符合开闭原则的,这个开闭原则更像是前面五项原则遵守程度的"平均得分",前面5项原则遵守的好,平均分自然就高,说明软件设计开闭原则遵守的好;如果前面5项原则遵守的不好,则说明开闭原则遵守的不好。

其实笔者认为,开闭原则无非就是想表达这样一层意思:用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了。当然前提是我们的抽象要合理,要对需求的变更有前瞻性和预见性才行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值