设计模式学习-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属性,这样要添加一个新的汽车类型只需要添加一个类就行了,削弱了汽车类和颜色类的耦合度

posted @ 2022-07-25 20:08  dronff  阅读(34)  评论(0)    收藏  举报