开放-封闭原则(The Open-Closed Principle)

1 定义

       软件实体(类、模块、函数等等)应该是可以扩展的,但是不可修改的。开放-封闭原则主要体现在两个方面:

  • 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
  • 对修改封闭,意味着一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。

返回目录

2 如何实现

       在OCP中,实现开放封闭的方法就是抽象编程,而不对具体编程,因为抽象相对稳定。让类依赖于固定的抽象,所以对修改就是封闭的;而通过面向对象的继承和多态机制,可以实现对抽象体的继承,通过覆写其方法来改变固有行为,实现新的扩展方法,所以对于扩展就是开放的。这是实施开放-封闭原则的基本思路,同时这种机制建立在两个基本的设计原则的基础上,这就是Liskov替换原则和合成/聚合复用原则。
       实现OCP原则的设计模式主要有模板模式、策略模式。而封装变化,是实现这一原则的重要手段,将经常发生变化的状态封装为一个类。具体设计模式的编写可以参考如下文章(4.1,4.2章节):
https://blog.csdn.net/weixin_37624828/article/details/106059837

2.1 问题: 一个糟糕的设计

代码清单:

  1. ShapeType.java --枚举类
  2. Point.java
  3. Shape.java
  4. Square.java
  5. Circle.java
  6. OcpDemo1.java

1 ShapeType.java

public enum ShapeType {
    /**
     * 圆
     */
    CIRCLE,
    /**
     * 方
     */
    SQUARE
}

2 Point.java

public class Point {
    private double x;
    private double y;

    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
    
    @Override
    public String toString() {
        return "Point{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
}

3 Shape.java

public abstract class Shape {
    ShapeType itsType;
}

4 Square.java

public class Square extends Shape {
   double itsSide;
   Point itsToLeft;

   public Square(ShapeType itsType, double itsSide, Point itsToLeft) {
       this.itsType = itsType;
       this.itsSide = itsSide;
       this.itsToLeft = itsToLeft;
   }

   public void drawSquare(){
       System.out.println("绘制方形");
       System.out.println(toString());
   }

   @Override
   public String toString() {
       return "Square{" +
               "itsSide=" + itsSide +
               ", itsToLeft=" + itsToLeft +
               ", itsType=" + itsType +
               '}';
   }
}

5 Circle.java

public class Circle extends Shape{
    double itsRadius;
    Point itsCenter;

    public Circle(ShapeType itsType, double itsRadius, Point itsCenter) {
        this.itsType = itsType;
        this.itsRadius = itsRadius;
        this.itsCenter = itsCenter;
    }

    public void drawCircle(){
        System.out.println("绘制圆形");
        System.out.println(toString());
    }

    @Override
    public String toString() {
        return "Circle{" +
                "itsRadius=" + itsRadius +
                ", itsCenter=" + itsCenter +
                ", itsType=" + itsType +
                '}';
    }
}

6 OcpDemo1.java

public class OcpDemo1 {
    public static void main(String[] args) {
        List<Shape> shapeList = new ArrayList<>();
        shapeList.add(new Circle(ShapeType.CIRCLE, 1, new Point(1, 2)));
        shapeList.add(new Square(ShapeType.SQUARE, 1, new Point(1, 2)));
        shapeList.add(new Square(ShapeType.SQUARE, 1, new Point(1, 2)));
        shapeList.add(new Circle(ShapeType.CIRCLE, 1, new Point(1, 2)));

        for (int i = 0; i < shapeList.size(); i++) {
            switch (shapeList.get(i).itsType){
                case CIRCLE:
                    ((Circle) shapeList.get(i)).drawCircle();
                    break;
                case SQUARE:
                    ((Square) shapeList.get(i)).drawSquare();
                    break;
                default:
                    System.out.println("非圆非方");
            }
        }
    }
}

       OcpDemo1中的main方法就不符合OCP原则,因为它对新的类型的添加不是封闭的,每次添加一个新类型就需要在switch菜单中添加一个选项。
       在实际工作中并非每一个判断条件都像上述选项中这么规范,一般的判断条件都是由逻辑操作符组合而成的复杂判断条件,因此这样的设计是一个糟糕的设计。

2.2 解决方案:遵循OCP

类图

在这里插入图片描述注:蓝色代表Shape类型是可以扩展的

代码清单:

  1. Shape.java --接口
  2. Circle.java
  3. Square.java
  4. OcpDemo2.java

1 Shape.java

public interface Shape {
    /**
     * 绘制形状方法
     */
    void draw();
}

2 Circle.java

public class Circle implements Shape{
    ShapeType itsType;
    double itsRadius;
    Point itsCenter;

    Circle(ShapeType itsType, double itsRadius, Point itsCenter) {
        this.itsType = itsType;
        this.itsRadius = itsRadius;
        this.itsCenter = itsCenter;
    }

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

    @Override
    public String toString() {
        return "Circle{" +
                "itsRadius=" + itsRadius +
                ", itsCenter=" + itsCenter +
                ", itsType=" + itsType +
                '}';
    }
}

3 Square.java

public class Square implements Shape {
    ShapeType itsType;
    double itsSide;
    Point itsToLeft;

    public Square(ShapeType itsType, double itsSide, Point itsToLeft) {
        this.itsType = itsType;
        this.itsSide = itsSide;
        this.itsToLeft = itsToLeft;
    }

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

    @Override
    public String toString() {
        return "Square{" +
                "itsSide=" + itsSide +
                ", itsToLeft=" + itsToLeft +
                ", itsType=" + itsType +
                '}';
    }
}

4 OcpDemo2.java

public class OcpDemo2 {
    public static void main(String[] args) {
        List<Shape> shapeList = new ArrayList<>();
        shapeList.add(new Circle(ShapeType.CIRCLE, 1, new Point(1, 2)));
        shapeList.add(new Square(ShapeType.SQUARE, 1, new Point(1, 2)));
        shapeList.add(new Square(ShapeType.SQUARE, 1, new Point(1, 2)));
        shapeList.add(new Circle(ShapeType.CIRCLE, 1, new Point(1, 2)));
        // 绘制图形
        drawShape(shapeList);
    }

    /**
     * 绘制图形
     * @param list 图形集合
     */
    private static void drawShape(List<Shape> list) {
        for (Shape shape : list) {
            shape.draw();
        }
    }
}

       如果list需要添加一个新类型时,drawShape方法无需做出修改,只需要实现一个新类型即可,这就遵循了开放-封闭原则。Shape类型是可以扩展的(遵循了开放),drawShape方法无需修改(遵循了封闭)。

3 结论

       在许多方面,OCP都是面向对象设计的核心所在。遵循这个原则可以体现面向对象技术的好处(灵活性、可重用性以及可维护性)。但是并不是只要使用面向对象语言就需要遵循这个原则,开发人员应该对程序中频繁变化的部分做出抽象,而不是对程序肆意抽象。抽象和拒绝抽象同样重要

返回目录

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值