设计模式六大原则
标签(空格分隔): 设计模式
- 单一职责
一个类,能引起其变化的原因只能有一个。如果一个类中,承担的职责越多,代码耦合度就越高,在修改需求时就会由于修改一个职责而影响另一个职责的使用。
反例:
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)尽量降低成员的访问权限。