六大设计原则,开闭原则

    xiaoxiao2021-12-14  19

    开闭原则定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。 这句话的意思是说,一个软件实体应该通过扩展来实现变化,而不是通过写该已有的代码来实现变化。同样的,我们在现实开发中,最乐意做的事情就是扩展一个类,而不是修改一个类,不管原有的代码写的多么优秀还是多么糟糕,让开发读懂原有的代码,而后再修改是一件非常痛苦的事情。

    我们来看这样一个例子,T先生开了一家书店,专门卖小说类的书籍,然后他写下了这样的一些代码。 书籍接口

    public interface IBook { //获得书籍名称 public String getName(); //获得书籍价格 public int getPrice(); //获得书籍作者 public String getAuthor(); }

    小说类

    public class NovelBook { //名称 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 getName() { return name; } public int getPrice() { return price; } public String getAuthor() { return author; } }

    书店售书类

    public class BookStore { private final static List<IBook> bookList = new ArrayList<IBook>(); //static静态模块初始化数据,实际项目中一般由持久层完成 static { bookList.add(new NovelBook("活着", 2000, "余华")); bookList.add(new NovelBook("许三观卖血记", 2000, "余华")); bookList.add(new NovelBook("一个人的记忆", 3000, "史铁生")); bookList.add(new NovelBook("平凡的世界", 3500, "路遥")); } public static void main(String[] args) { NumberFormat format = NumberFormat.getCurrencyInstance(); format.setMaximumFractionDigits(2); System.out.println("--------书店卖出去的书籍记录如下--------"); for (IBook book: bookList) { System.out.println("书籍名称: " + book.getName() + "\t书籍作者: " + book.getAuthor() + "\t书籍价格" + format.format(book.getPrice()/100.0) + "元"); } } }

    但是T先生小说书卖的并不畅销,于是他想出了打折促销,那便是意味着代码变化要来了。那么怎么修改,我们代码的所需承受的代价最小,这是我们要思考的。 1.T先生首先想到了修改IBook接口,往里面加上一个getOffPrice()的促销方法,但是不想不知道,一想吓一跳,只要动了接口,就要动全部的实现接口的方法,哇,真恐怖。方案否定。 2.然后T先生想到我可以修改NovelBook,修改修改getPrice()方法,加上打折的逻辑,这样就只需要修改这样一个地方啦。但是这样的设计在实际开发中是不提倡的。原因有两点,第一我们的方法中没有了获得书籍原价的方法,第二点,我们在开发中不仅仅只有开发人员,还有测试人员,这样的修改,会导致测试人员需要修改他写的对这个类的测试,可能会改的面目全非,这是测试人员所不愿意看到的。 3.终于,T先生想到了开闭原则,“一个软件实体应该对扩展开放,对修改关闭”,其实反过头来看前面两个方案,他们都是修改了原来的代码。那应该怎么扩展呢?来看一下T先生写的这个类。

    public class OffNovelBook extends NovelBook { public OffNovelBook(String name, int price, String author) { super(name, price, author); } @Override public int getPrice() { return super.getPrice() * 80 / 100; } }

    T先生继承(扩展)了NovelBook类,并复写了getPrice()方法。 然后BookStore类修改为

    public class BookStore { private final static List<IBook> bookList = new ArrayList<IBook>(); //static静态模块初始化数据,实际项目中一般由持久层完成 static { //修改的地方 bookList.add(new OffNovelBook("活着", 2000, "余华")); bookList.add(new OffNovelBook("许三观卖血记", 2000, "余华")); bookList.add(new OffNovelBook("一个人的记忆", 3000, "史铁生")); bookList.add(new OffNovelBook("平凡的世界", 4500, "路遥")); } public static void main(String[] args) { NumberFormat format = NumberFormat.getCurrencyInstance(); format.setMaximumFractionDigits(2); System.out.println("--------书店卖出去的书籍记录如下--------"); for (IBook book: bookList) { System.out.println("书籍名称: " + book.getName() + "\t书籍作者: " + book.getAuthor() + "\t书籍价格" + format.format(book.getPrice()/100.0) + "元"); } } }

    开闭原则也提出了一个重要的约束,叫抽象约束。 1. 通过接口或抽象类约束扩展,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的Public方法; 2. 参数类型、引用对象尽量使用接口或者抽象类,而不是实现类; 3. 抽象层尽量保持稳定,一旦确定就不允许改变;

    T先生最近拓展了业务,他开始卖计算机类书籍。计算机类书籍除了书名,价格,作者之外还应该有个字段来分类是数据库类书籍,还是编程语言类书籍等等。T先生熟练掌握了开闭原则,不慌不忙的扩展了这些代码 T先生首先扩展了IBook接口

    public interface IcomputerBook extends IBook { //计算机书籍是有一个范围 public String getScope(); }

    然后在实现这个IComputerBook接口

    public class ComputerBook implements IcomputerBook { //名称 private String name; //售价 private int price; //作者 private String author; //书籍范围 private String scope; public ComputerBook(String name, int price, String author, String scope) { this.name = name; this.price = price; this.author = author; this.scope = scope; } @Override public String getScope() { return scope; } @Override public String getAuthor() { return author; } @Override public int getPrice() { return price; } @Override public String getName() { return name; } }

    最后我们在BookStore类中只需要修改一个地方就好

    public class BookStore { private final static List<IBook> bookList = new ArrayList<IBook>(); //static静态模块初始化数据,实际项目中一般由持久层完成 static { bookList.add(new OffNovelBook("活着", 2000, "余华")); bookList.add(new OffNovelBook("许三观卖血记", 2000, "余华")); bookList.add(new OffNovelBook("一个人的记忆", 3000, "史铁生")); bookList.add(new OffNovelBook("平凡的世界", 4500, "路遥")); //修改的地方 bookList.add(new ComputerBook("第一行代码", 7500, "郭霖", "编程语言")); } public static void main(String[] args) { NumberFormat format = NumberFormat.getCurrencyInstance(); format.setMaximumFractionDigits(2); System.out.println("--------书店卖出去的书籍记录如下--------"); for (IBook book: bookList) { System.out.println("书籍名称: " + book.getName() + "\t书籍作者: " + book.getAuthor() + "\t书籍价格" + format.format(book.getPrice()/100.0) + "元"); } } }
    转载请注明原文地址: https://ju.6miu.com/read-971080.html

    最新回复(0)