欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

开闭原则

程序员文章站 2022-03-15 17:01:14
...

定义
一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

也就是说,如果修改或者添加一个功能,应该是通过扩展原来的代码,而不是通过修改原来的代码。

举个例子,一本书有价格,书名,年份,程序表示就是:
图解:
开闭原则
用代码表示为:
先创建一个图书馆接口:

public interface Library {
    double getPrice();
    String getBookName();
    String getYear();
}

创建书类实现它:

public class Book implements Library{
    private double price;
    private String bookName;
    private String year;
    public Book(double price,String bookName,String year){
        this.bookName = bookName;
        this.price = price;
        this.year = year;
    }

    public double getPrice() {
        return price;
    }

    public String getBookName() {
        return bookName;
    }

    public String getYear() {
        return year;
    }
}

然后购买书:

public class BuyBook {
    public static void main(String[] args) {
        Library book = new Book(100.0,"java开放原则","2008");
        System.out.println("书名:"+book.getBookName());
        System.out.println("价格:"+book.getPrice());
        System.out.println("年份:"+book.getYear());
    }
}

运行结果:
开闭原则
到这里都没有没有问题,但是问题自己来了,假如说今天是读书日,图书都8折出售,怎么办?
当然是赶紧修改啊,但是,假如说修改了getPrice()方法,那恢复原价了是不是还要改,以后再打折是不是还要改,这明显就违背了开闭原则的修改关闭。那么怎么修改呢,当然是扩展了!
做了如下改变:
首先添加一个子类继承图书类,在其中打折,但是要遵守里氏替换原则,所以添加一个方法:

public class BookSell extends Book{

    public BookSell(double price, String bookName, String year) {
        super(price, bookName, year);
    }
    public double getUserPrice(){
        return (double) (getPrice()*0.6);
    }
}

购买类:

public class BuyBook {
    public static void main(String[] args) {
        Library book = new BookSell(100.0,"java开放原则","2008");
        System.out.println("书名:"+book.getBookName());
        System.out.println("价格:"+((BookSell) book).getUserPrice());
        System.out.println("年份:"+book.getYear());
    }
}

输出结果:
开闭原则
这里就扩展了它的功能,而其它功能并没有受到影响。
图解:
开闭原则

如何使用开闭原则

第一:抽象约束
抽象是对一组事物的通用描述,没有具体的实现,也就表示它可以有非常多的可能性,可以跟随需求的变化而 变化。因此,通过接口或抽象类可以约束一组可能变化的行为,并且能够实现对扩展开放,其包含三层含义:

- 通过接口或抽象类约束扩散,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法。
- 参数类型,引用对象尽量使用接口或抽象类,而不是实现类,这主要是实现里氏替换原则的一个要求
- 抽象层尽量保持稳定,一旦确定就不要修改

第二:元数据(metadata)控件模块行为
编程是一个很苦很累的活,那怎么才能减轻压力呢?答案是尽量使用元数据来控制程序的行为,减少重复开发。什么是元数据?用来描述环境和数据的数据,通俗的说就是配置参数,参数可以从文件中获得,也可以从数据库中获得。

第三:制定项目章程
在一个团队中,建立项目章程是非常重要的,因为章程是所有人员都必须遵守的约定,对项目来说,约定优于配置。这比通过接口或抽象类进行约束效率更高,而扩展性一点也没有减少。

第四:封装变化
对变化封装包含两层含义:
(1)将相同的变化封装到一个接口或抽象类中
(2)将不同的变化封装到不同的接口或抽象类中,不应该有两个不同的变化出现在同一个接口或抽象类中。
封装变化,也就是受保护的变化,找出预计有变化或不稳定的点,我们为这些变化点创建稳定的接口。

相关标签: java 开闭原则