Open-Closed Principle (Open-Closed Principle)

        A software entity such as classes, modules and functions should be open for extension and closed for modification.

        The definition of the open-closed principle has told us very clearly: a software entity should be developed for extension and closed for modification, which means that a software entity should achieve change through expansion rather than modification . Is it a software entity?

        The software entity consists of the following parts:

  • A module divided according to certain logical rules in a project or software product.
  • Abstractions and classes.
  • method.

        The existence of a piece of software will always change. Since change is an unchanging fact, we should try our best to adapt to these changes during design, so as to improve the stability and flexibility of the project, and truly "embrace change". The principle of opening and closing tells us that we should try our best to realize the change by expanding the behavior of the software entity, rather than by modifying the existing code to complete the change. It is a principle formulated for the future events of the software entity to constrain the current development design. Let's illustrate what the open-close principle is. Take the bookstore selling books as an example, as shown in Figure 1-1.

Picture 1-1

                                If you don’t understand the meaning of this picture, you can read this article: Article

        IBook defines three properties of data: name, price and author. The novel class NovelBook is a specific implementation
class, which is the general name of all novel books, BookStore refers to the bookstore, and the IBook interface is shown in the code list 2-1.

//代码清单2-1 书籍接口
public interface IBook {
    //书籍有名称
    public String getName();
    //书籍有售价
    public int getPrice();
    //书籍有作者
    public String getAuthor();
}

        At present, the bookstore only sells novel books, and the novel category is shown in the code list 2-2.

//代码清单2-2 小说类。
public class NovelBook implements IBook {
    //书籍名称
    private String name;
    //书籍的价格
    private int price;
    //书籍的作者
    private String author;
    //通过构造函数传递书籍数据
    public NovelBook(String _name,int _price,String _author){
        this.name = _name;
        this.price = _price;
        this.author = _author;
    }/
    /获得作者是谁
    public String getAuthor() {
        return this.author;
    }/
    /书籍叫什么名字
    public String getName() {
        return this.name;
    }/
    /获得书籍的价格
    public int getPrice() {
        return this.price;
    }
}

        The process of selling books in a bookstore is shown in Listing 2-3.

        Note that it is not wrong for us to define the price as an int type. When dealing with currency in non-financial projects,
2-digit precision is generally used. The usual design method is to expand by 100 times during the calculation process, and then shrink by 100 times when it needs to be displayed. , to reduce
the error caused by precision.

//代码清单2-3所示
public class BookStore {
    private final static ArrayList<IBook> bookList = new ArrayList<IBook>();
    //static静态模块初始化数据, 实际项目中一般是由持久层完成
    static{
        bookList.add(new NovelBook("天龙八部",3200,"金庸"));
        bookList.add(new NovelBook("巴黎圣母院",5600,"雨果"));
        bookList.add(new NovelBook("悲惨世界",3500,"雨果"));
        bookList.add(new NovelBook("金瓶梅",4300,"兰陵笑笑生"));
    }

    //模拟书店买书
    public static void main(String[] args) {
        NumberFormat formatter = NumberFormat.getCurrencyInstance();
        formatter.setMaximumFractionDigits(2);
        System.out.println("-----------书店卖出去的书籍记录如下: -----------");
        for(IBook book:bookList){
            System.out.println("书籍名称: " + book.getName()+"\t书籍作者: "
            book.getAuthor()+"\t书籍价格: "+ formatter.format(
            book.getPrice()/100.0)+"元");
        }
    }
   
}

        A static module is declared in BookStore to realize the initialization of data, and the running results are as follows:

-----------------书店卖出去的书籍记录如下: --------------
书籍名称: 天龙八部 书籍作者: 金庸 书籍价格: ¥32.00元
书籍名称: 巴黎圣母院 书籍作者: 雨果 书籍价格: ¥56.00元
书籍名称: 悲惨世界 书籍作者: 雨果 书籍价格: ¥35.00元
书籍名称: 金瓶梅 书籍作者: 兰陵笑笑生 书籍价格: ¥43.00元

        Now that the project has been completed, at this time, the product manager proposed: all books above 40 yuan will be sold with a 10% discount, and other books
will be sold with a 20% discount. For projects that have already been put into production, this is a change, so how do we deal with this change? There are three ways to solve this problem:

  • Modify the interface:

        Add a new method getOffPrice() on IBook, which is specially used for discount processing, and all implementation classes implement this method. But the consequence of this modification is that the implementation class NovelBook needs to be modified, and the main method in BookStore should also be modified. At the same time, IBook as an interface should be stable and reliable, and should not change frequently, otherwise the function of the interface as a contract will lose its effectiveness. Therefore, this solution is definitely not acceptable.

  • Modify the implementation class:

        It is obviously achievable to modify the method in the NovelBook class, directly realize the discount processing in getPrice(), or dynamically replace the class file, but this solution has a more obvious error, for example, we modify this getPrice( ) method, then we will not be able to see the original price of the book, and this solution will not work.

  • Variation through extension

        Add a subclass of OffNovelBook, override the getPrice method, modify the high-level module (that is, the static static module initialization data), and generate a new object through the OffNovelBook class to complete the discount function without modifying the interface or modifying the original The class of the static static module belongs to the high-level module, which is generated by the persistence layer. When the business rules change, the high-level module must be partially changed to adapt to the new business. Changes should be as few as possible to prevent the spread of change risks .

Figure 1-2, the expanded bookstore sales class

diagram

                The OffNovelBook class inherits NovelBook and overrides the getPrice method without modifying the original code. The newly added subclass OffNovelBook is shown in Listing 2-4.

//代码清单2-4所示
public class OffNovelBook extends NovelBook {
    public OffNovelBook(String _name,int _price,String _author){
        super(_name,_price,_author);
    }//覆写销售价格
    @Override
    public int getPrice(){
        //原价
        int selfPrice = super.getPrice();
        int offPrice=0;
        if(selfPrice>4000){ //原价大于40元, 则打9折
            offPrice = selfPrice * 90 /100;
        }else{
            offPrice = selfPrice * 80 /100;
        }
        return offPrice;
    }
}

        It's very simple, just override the getPrice method, and complete the newly added business through extension. The bookstore class BookStore needs
to rely on subclasses, and the code is slightly modified, as shown in code list 2-5.

//代码清单2-5所示
public class BookStore {
    private final static ArrayList<IBook> bookList = new ArrayList<IBook>();
    //static静态模块初始化数据, 实际项目中一般是由持久层完成
    static{
        bookList.add(new OffNovelBook("天龙八部",3200,"金庸"));
        bookList.add(new OffNovelBook("巴黎圣母院",5600,"雨果"));
        bookList.add(new OffNovelBook("悲惨世界",3500,"雨果"));
        bookList.add(new OffNovelBook("金瓶梅",4300,"兰陵笑笑生"));
    }//模拟书店买书
    public static void main(String[] args) {
        NumberFormat formatter = NumberFormat.getCurrencyInstance();
        formatter.setMaximumFractionDigits(2);
        System.out.println("-----------书店卖出去的书籍记录如下: -----------");
        for(IBook book:bookList){
            System.out.println("书籍名称: " + book.getName()+"\t书籍作者: "
            book.getAuthor()+"\t书籍价格: "+ formatter.format(
            book.getPrice()/100.0)+"元");
        }
    }
}

         We only modified the static static module, and the other places did not move.

-----------------书店卖出去的书籍记录如下: --------------
书籍名称: 天龙八部 书籍作者: 金庸 书籍价格: ¥25.60元
书籍名称: 巴黎圣母院 书籍作者: 雨果 书籍价格: ¥50.40元
书籍名称: 悲惨世界 书籍作者: 雨果 书籍价格: ¥28.00元
书籍名称: 金瓶梅 书籍作者: 兰陵笑笑生 书籍价格: ¥38.70元

        OK,

The reference document comes from: Zen of Design Patterns.
 

Guess you like

Origin blog.csdn.net/fry3309/article/details/123582415