设计模式三

128 阅读4分钟

这是我参与更文挑战的第15天,活动详情查看: 更文挑战

设计模式

在前两篇设计模式一设计模式二我们已经讲了四种原则,接下来讲解的是开闭原则和迪米特法则。

开闭原则

最重要最基础的原则,对扩展开放,对修改关闭。通过使用接口和抽象类来实现在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。

比如我们绘制图形,起初我们只绘制矩形和圆形,代码是这样写的

package com.wangscaler.openclose;

/**
 * @author wangscaler
 * @date 2021.06.17 11:14
 */

public class OpenClosePrinciple {
    public static void main(String[] args) {
        Graphic graphic = new Graphic();
        graphic.drawRectangle(new Rectangle());
        graphic.drawCircular(new Circular());
    }

    static class Graphic {
        public void drawShape(Shape shape) {
            if (shape.type == 1) {
                drawCircular(shape);
            } else if (shape.type == 2) {
                drawRectangle(shape);
            }
        }

        public void drawRectangle(Shape shape) {
            System.out.println("绘制矩形...");
        }

        public void drawCircular(Shape shape) {
            System.out.println("绘制圆形...");
        }
    }

    static class Shape {
        int type;
    }

    static class Circular extends Shape {
        Circular() {
            super.type = 1;
        }
    }

    static class Rectangle extends Shape {
        Rectangle() {
            super.type = 2;
        }
    }
}

当我们添加新的图形梯形的时候,按照这种方式的话代码就得这样改

错误方式

package com.wangscaler.openclose;

/**
 * @author wangscaler
 * @date 2021.06.17 11:14
 */

public class OpenClosePrinciple1 {
    public static void main(String[] args) {
        Graphic graphic = new Graphic();
        graphic.drawRectangle(new Rectangle());
        graphic.drawCircular(new Circular());
        graphic.drawTrapezoid(new Trapezoid());
    }

    static class Graphic {
        public void drawShape(Shape shape) {
            if (shape.type == 1) {
                drawCircular(shape);
            } else if (shape.type == 2) {
                drawRectangle(shape);
            }
            else if(shape.type == 3){
                drawTrapezoid(shape);
            }
        }

        public void drawRectangle(Shape shape) {
            System.out.println("绘制矩形...");
        }

        public void drawCircular(Shape shape) {
            System.out.println("绘制圆形...");
        }

        public void drawTrapezoid(Shape shape) {
            System.out.println("绘制梯形...");
        }
    }

    static class Shape {
        int type;
    }

    static class Circular extends Shape {
        Circular() {
            super.type = 1;
        }
    }

    static class Rectangle extends Shape {
        Rectangle() {
            super.type = 2;
        }
    }

    static class Trapezoid extends Shape {
        Trapezoid() {
            super.type = 3;
        }
    }
}

这样虽然可以拿到正确结果,但是改的代码较多,并不能实现热拔插效果,我们不仅修改了提供方的代码(增加了Trapezoid),还修改了使用方的代码(Graphic)。我们应该将Shape变成抽象类,有新的图形时,只需要增加新的图形类去继承这个抽象类就可以了

正确的方式

package com.wangscaler.openclose;

/**
 * @author wangscaler
 * @date 2021.06.17 11:14
 */

public class OpenClosePrinciple2 {
    public static void main(String[] args) {
        Graphic graphic = new Graphic();
        graphic.drawShape(new Rectangle());
        graphic.drawShape(new Circular());
    }

    static class Graphic {
        public void drawShape(Shape shape) {
            shape.draw();
        }

    }

    static abstract class Shape {
        public abstract void draw();
    }

    static class Circular extends Shape {
        @Override
        public void draw() {
            System.out.println("绘制圆形...");
        }
    }

    static class Rectangle extends Shape {
        @Override
        public void draw() {
            System.out.println("绘制矩形...");
        }
    }
}

这时候我们增加新的图形矩形,只需要修改成

package com.wangscaler.openclose;

/**
 * @author wangscaler
 * @date 2021.06.17 11:14
 */

public class OpenClosePrinciple3 {
    public static void main(String[] args) {
        Graphic graphic = new Graphic();
        graphic.drawShape(new Rectangle());
        graphic.drawShape(new Circular());
        graphic.drawShape(new Trapezoid());
    }

    static class Graphic {
        public void drawShape(Shape shape) {
            shape.draw();
        }

    }

    static abstract class Shape {

        public abstract void draw();
    }

    static class Circular extends Shape {

        @Override
        public void draw() {
            System.out.println("绘制圆形...");
        }
    }

    static class Rectangle extends Shape {
        @Override
        public void draw() {
            System.out.println("绘制矩形...");
        }
    }

    static class Trapezoid extends Shape {
        @Override
        public void draw() {
            System.out.println("绘制梯形...");
        }
    }
}

总结: 开闭原则对扩展开放,对修改关闭。我们新增梯形,只需要新增加梯形这个类,让我们的梯形去继承shape抽象类并实现抽象类的方法,此时我们不需要修改原有的代码,就实现了我们想要的结果。

迪米特法则

一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。即只和直接的朋友(方法参数、成员变量、方法返回值)通信。

比如 学校校长想查某个班的人数,所以

package com.wangscaler.leastknowledgeprinciple;

import java.util.ArrayList;
import java.util.List;

/**
 * @author wangscaler
 * @date 2021.06.17 14:09
 */
public class LeastKnowledgePrinciple {
    public static void main(String[] args) {
        Principal principal = new Principal();
        principal.commond(new Teacher());
    }

    static class Principal {
        public void commond(Teacher teacher) {
            List<Student> students = new ArrayList<Student>();
            for (int i = 0; i < 20; i++) {
                students.add(new Student());
            }
            teacher.count(students);
        }
    }

    static class Teacher {
        public void count(List<Student> students) {
            System.out.println("学生的数量是:" + students.size());
        }
    }

    static class Student {
    }
}

在这里,我们在校长的commond的方法里出现了Student,他就不是方法参数、成员变量还不是方法返回值,所以说Student不是Principal的直接朋友,这样就是违反了迪米特法则。那么应该怎么修改呢,因为Student和Teacher是直接的朋友

package com.wangscaler.leastknowledgeprinciple;

import java.util.ArrayList;
import java.util.List;

/**
 * @author wangscaler
 * @date 2021.06.17 14:09
 */
public class LeastKnowledgePrinciple1 {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<Student>();
        for (int i = 0; i < 20; i++) {
            students.add(new Student());
        }
        Principal principal = new Principal();
        principal.commond(new Teacher(students));
    }

    static class Principal {
        public void commond(Teacher teacher) {
            teacher.count();
        }
    }

    static class Teacher {
        private List<Student> students;

        public Teacher(List<Student> students) {
            this.students = students;
        }

        public void count() {
            System.out.println("学生的数量是:" + students.size());
        }
    }

    static class Student {
    }
}

学生成为老师的成员变量,老师和学生是直接朋友,校长和老师是直接朋友。

总结: 从上述例子可以看出,迪米特法则可以降低耦合。尽量避免不是直接的朋友(局部变量)出现在类中。