六大设计原则,开闭原则

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

我们来看这样一个例子,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) + "元");
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值