设计模式六大原则
标签(空格分隔): 设计模式
单一职责
一个类,能引起其变化的原因只能有一个。如果一个类中,承担的职责越多,代码耦合度就越高,在修改需求时就会由于修改一个职责而影响另一个职责的使用。
反例:class Terrestrial{ public void breathe(String animal){ System.out.println(animal+"呼吸空气"); } } class Aquatic{ public void breathe(String animal){ System.out.println(animal+"呼吸水"); } } public class Client{ public static void main(String[] args){ Terrestrial terrestrial = new Terrestrial(); terrestrial.breathe("牛"); terrestrial.breathe("羊"); terrestrial.breathe("猪"); Aquatic aquatic = new Aquatic(); aquatic.breathe("鱼"); } }
问题:如果修改鱼吸水,就会破坏单一原则,所以就需要把类分成陆生和水生。但其实在实际项目中,往往会遇到在项目开始时,并不能考虑到后期需求的更改,会不会使原先设计的类破坏单一原则。
开放-封闭原则
一个类,只能够拓展,不能够修改。对拓展开放,当需求变更时,可以对现有代码进行拓展;对修改封闭,类一旦设计完成,就不要对其进行任何修改。具体做法,核心思想是对抽象编程,而不是对具体编程,抽象要相对稳定,让类依赖于固定的抽象,就是对修改封闭(不去修改父类方法)。对扩展开放,通过面向对象的思想使用继承或多态去实现子类,子类在父类函数基础上去完善父类提供的方法。
反例:public class BankProcess { //存款 public void Deposite(){} //取款 public void Withdraw(){ } //转账 public void Transfer(){} } public class BankStaff { private BankProcess bankpro = new BankProcess(); public void BankHandle(Client client) { switch (client.Type) { //存款 case "deposite": bankpro.Deposite(); break; //取款 case "withdraw": bankpro.Withdraw(); break; //转账 case "transfer": bankpro.Transfer(); break; } } }
问题:这样的设计,一旦需求更改,需要新加基金功能,就会对违反开放-封闭原则,所以应该修改成抽象类或接口,然后由抽象类(接口)去派生(实现)。在应对新需求时,就可以添加新的子类(实现)去应对需求变更,就不会违背开放-封闭原则。
里氏替换原则
子类行必须能够替换掉他的父类型。一个软件单位,其子类可以替换其父类,且软件单位功能不受影响,父类才真正被复用,子类也就能够在父类基础上扩展自己的方法。在设计时尽量充抽象类继承而避免从具体类继承。
尽量不去重写或者重载父类方法,因为可能存在多个子类继承抽象基类,如果其中一个子类修改父类方法,就很可能对其他继承的子类造成影响。class A{ public int func1(int a, int b){ return a-b; } } public class Client{ public static void main(String[] args){ A a = new A(); System.out.println("100-50="+a.func1(100, 50)); System.out.println("100-80="+a.func1(100, 80)); } } // 后来,我们需要增加一个新的功能:完成两数相加,然后再与100求和,由类B来负责。即类B需要完成两个功能 class B extends A{ public int func1(int a, int b){ return a+b; } public int func2(int a, int b){ return func1(a,b)+100; } } public class Client{ public static void main(String[] args){ B b = new B(); 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)); } }
依赖倒置原则
抽象高层模块不应该依赖底层模块,面向过程开发中上层调用下层,就造成了上层依赖下层,其中若下层发生变动,则会造成上层调用模块全部都需要改动,而依赖倒转就解决了这一问题。(Spring IOC)合成/聚合原则
尽量使用合成/聚合,尽量不要使用类继承,子类与其父类关系密切,父类的修改必然会对子类造成影响,而如果不小心对父类方法进行修改,就会造成子类错误的发生,这种依赖关系增加了类与类之间的依赖关系,提高了耦合度。
组合与聚合区别
- 迪米特法则
如果两个类之间不必直接通信,则这两个类就不应该直接相互作用,其中一个类需要调用另一个类的某一个方法的话,可以通过第三方进行转发调用。其核心思想就是类与类之间松耦合,类之间耦合度越低,其复用性越强。
(1)优先考虑将一个类设置成不变类。
(2)尽量降低一个类的访问权限。
(3)谨慎使用Serializable。
(4)尽量降低成员的访问权限。