设计模式学习-01【六大原则】
开闭原则
开闭原则规定"软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的"
抽象接口
public interface AbstractTheme { void printColor(); }
public class RedTheme implements AbstractTheme{ @Override public void printColor() { System.out.println("红色"); } }
public class GreenTheme implements AbstractTheme{ @Override public void printColor() { System.out.println("绿色"); } }
public class MyApplication { static AbstractTheme theme; public static void main(String[] args) { //初始化一个红色主题 AbstractTheme abstractTheme = new RedTheme(); setTheme(abstractTheme); theme.printColor(); } static void setTheme(AbstractTheme theme){ MyApplication.theme = theme; } }
如果还需要加一个蓝色主题,只需要新增一个蓝色主题类,而不用在原来的代码上改变。
这就是所说的对外扩展,但不能修改之前的代码
里氏替换原则
里氏替换原则要求:子类只能提供新的功能,但不能重写其父类(基类)的方法(子类可以代替其基类对象)
反例:
现有一个矩形类
public class Rectangle { Integer width; Integer height; public void setHeight(Integer height) { this.height = height; } public void setWidth(Integer width) { this.width = width; } public Integer getHeight() { return height; } public Integer getWidth() { return width; } }
还有一个正方形类
public class Square extends Rectangle{ @Override public void setHeight(Integer height) { super.setHeight(height); super.setWidth(height); } @Override public void setWidth(Integer width) { super.setWidth(width); setHeight(width); } }
在本例中,正方形类继承自矩形类,但是重写了其父类的方法,不满足里氏替换原则
会导致什么情况呢?看例子
public class MyApplication { public static void main(String[] args) { Rectangle rectangle = new Rectangle(); rectangle.setWidth(1); rectangle.setHeight(5); expand(rectangle); System.out.println("矩形的宽度:"+rectangle.getWidth()); System.out.println("矩阵的长度:"+rectangle.getHeight()); } /** * 将矩形的宽度拓展到比矩阵长度长 */ static void expand(Rectangle rectangle){ while (rectangle.getWidth()<=rectangle.getHeight()){ rectangle.setWidth(rectangle.getWidth()+1); } } }
在上面的代码中,expand方法负责将矩阵的宽度扩展到比其长度长,当输入是Rectangle的对象时,没有问题
但当输入的是其子类Square时,方法便会进入死循环
解决方案:
抽象一个Quadrangle接口,接口中有两个方法 setWidth和setHeight,这样就可以避免违背里氏替换原则
依赖倒转原则
依赖倒转原则要求:抽象接口(类)不能直接依赖一个具体的类,应该去依赖那个具体的类的上层类或接口
比如:现在有一个鼠标抽象类,鼠标类中有一个安装电池的方法
public abstract class Mouse { abstract void installBattery(LanfuBattery lanfuBattery); }
但是这个方法的参数类型却是一个具体的类(蓝符电池),
很显然不符合依赖倒转原则,
试想如果现在有其他品牌的电池可以使用,难道要重载一个方法吗
所以正确的做法是将给电池抽象一个Battery抽象类或者接口
接口隔离原则
接口隔离原则要求:程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口,而一个类对另一个类/接口的实现不应该实现不需要的方法
例子:现有一个动物抽象类,类中有两个抽象方法【进食|捕猎】
public abstract class Animal { //进食 abstract void eat(); //捕猎 abstract void hunt(); }
还有一个人类类,实现了Animal类
public class People extends Animal{ @Override public void eat() { System.out.println("人吃饭了"); } @Override public void hunt() { } }
在此类中,People类实现了不必要的方法(捕猎),很明显违背了接口隔离原则
正确做法是,将Eat和Hunt这两个行为抽象成两个接口,人类只需要去实现Eat接口
迪米特原则
迪米特原则要求:一个类对于其他类知道的越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话。
例子:
现在有一个明星类,明星有一个唱歌方法
public class Star { void sing(){ System.out.println("唱歌"); } }
现在要让明星能有与粉丝见面的能力和卖专辑的能力,应该是在建一个Proxy(代理公司)类,用来赋予明星这些能力,这样可以减少明星这个类对其他类的依赖,而只专心于他自己的业务
合成复用原则
合成复用原则要求:类应该更多的使用组合和聚合的方式来替代继承。
例子:
public abstract class Car { }
//电动汽车 public class ElectroCar extends Car{ }
//白色电动汽车 public class WhiteElectroCar extends ElectroCar{ }
这样很显然违背了合成复用原则,如果以后还要添加一个黑色电动汽车则还需要再添加一个新的类,并且这种添加的层级越往上,添加的类则越多,
因为父类与子类的耦合度过高,父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。
所以此时的解决方案应该是再car中添加一个color属性,这样要添加一个新的汽车类型只需要添加一个类就行了,削弱了汽车类和颜色类的耦合度
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号