6大设计原则-开闭原则

开闭原则

开闭原则是java世界里最基础的设计原则,他指导我们如何建立一个稳定、灵活的系统,先来看开闭原则的定义:
Software entities like classes,modules and functions should be open for extension but close for modifications.(一个软件的实体如类,模块和函数应该对扩展开放,对修改关闭)
我们做一件事,或者选择一个方向,一般要经历三个步骤:what——是什么,why——为什么,How——怎么做(简称3W)(这是完成一个目标的基本过程,可以在各个方面去实践这个过程)。对于开闭原则,我们也采用这个三步来分析,即什么是开闭原则,为什么要使用开闭原则,怎么使用开闭原则。

  1. 开闭原则的庐山真面目

开闭原则的定义非常明确的告诉我们:软件实体应该对扩展开放,对修改关闭,其含义是说一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。
那什么又是软件实体呢?软件的实体包括以下几个部分:

  • 项目或软件产品中按照一定的逻辑规则划分的模块;
  • 抽象和类;
  • 方法。
    一个软件产品只要在生命期内,都会发生变化,既然变化是一个既定的事实,我们就应该在设计的时候尽量适应这些变化,以提高项目的稳定性和灵活性,真正实现拥抱变化。开闭原则告诉我们尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有代码来完成变化,他是为软件实体的未来事件而制定的对现行开发设计进行约束的一个原则。
    下面以书店销售书籍为例,其类图6-1:


    6-1

    代码如下:

public interface IBook {
    String getName();
    int getPrice();
    String getAuthor();
}
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;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public int getPrice() {
        return this.price;
    }

    @Override
    public String getAuthor() {
        return this.author;
    }
}
public class BookStore {
    private final static ArrayList<IBook> bookList = new ArrayList();

    static {
        bookList.add(new NovelBook("天龙八部",3200,"金庸"));
        bookList.add(new NovelBook("巴黎圣母院",5600,"雨果"));
        bookList.add(new NovelBook("悲惨世界",3500,"雨果"));
        bookList.add(new NovelBook("金瓶梅",3500,"兰陵笑笑生"));
    }

    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)+"元");
        }
    }
}

注意:这个地方价格定义为int类型并不是错误,在非金融类的项目中对货币的处理时,一般取2位精度,通常的设计方法是在运算过程中扩大100倍,在需要展示时在缩小100倍,减少精度带来的误差。(这个在计算的时候好像就比较麻烦一点,也不能保证在乘除运算的时候结果一定是整除的,缺点好像还是很明显的,当然仅仅是展示的话没什么问题

那么这样的设计怎么去处理需求变化的情况呢,书籍的价格可能会随着做活动或是其他情况会有折扣调整之类的,现在以打折销售举例:所有40元以上的书籍九折销售,其他的8折销售,有一下三种方法可以处理这种场景:

  • 修改接口
    在IBook上新增加一个getOffPrice(),专门用于进行打折处理,所有的实现类实现该方法,但是修改的后果就是,实现该接口的类需要修改,BookStore中的main方法也修改,同时IBook作为接口应该是稳定可靠的,不应该经常变化,否则接口作为契约的作用就失去效能了(我们往往用接口或是抽象去做依赖是为了设计的结构更方便扩展和保持稳定性,但是接口设计好后不应该在去修改,除非万不得已,否者改动接口的结果会导致更多的地方需要改动

  • 修改实现类
    修改NovelBook中的方法,直接在getPrice()中实现打折处理,原书中认为在么些情况下这是一个好办法(可能实际中我们很多情况就是这样处理的,但是我个人感觉这个还是有问题,这个打折活动可能有时间限制,这个也可以解决,可以通过加逻辑判断是否走打折逻辑,但是根据这个开闭原则,对修改关闭,这个肯定不是合理的做法

  • 通过扩展实现变化
    增加一个子类offNovelBook,覆写getPrice方法,高层次的模块也就是static静态模块区)通过offNovelBook类产生新的对象,完成业务对系统的最小化开发,类图6-2:

    6-2

    这就是通过OffNovelBook去继承NovelBook然后覆写OffNovelBook非getPrice方法,然后修改BookStore的静态代码块的地方,将实现类改为OffNovelBook,那么获取的价格就是打折的价格呢(这个原则给我们处理业务变更的情况下提供了一种解决问题的思路,这块具体的运用看实际怎么做,接下来的23中设计模式是根据这六大原则总结的实现
    注意:开闭原则对扩展开放,对修改关闭,并不意味着不做任何修改,低层模块的变化,必然要有高层模块进行耦合,否则就是一个孤立无意义的代码片段。
    这一原则原书有更详细的的解释,这个原则很虚包含很广,具体的理解通过后续的设计模式的设计思维去加深 。

内容来自《设计模式之禅》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • 目录: 设计模式六大原则(1):单一职责原则 设计模式六大原则(2):里氏替换原则 设计模式六大原则(3):依赖倒...
    加油小杜阅读 716评论 0 1
  • 设计模式六大原则 开闭原则 开闭原则,是说对于软件实体(类、模块、函数等等)应该可以拓展,但是不可修改 这句话有两...
    ChaLLengerZeng阅读 871评论 0 0
  • 设计模式6大原则 转自:http://www.cnblogs.com/devinzhang/archive/201...
    犀利的小眼神阅读 427评论 0 1
  • 程序设计的6大原则: 单一职责原则里氏替换原则依赖倒置原则接口隔离原则迪米特法则开闭原则 从根本学好,理解为什么要...
    silencefun阅读 2,390评论 1 4
  • 好似飞来雪, 心生欢喜悦。 春枝绽梨花, 香梦朝朝彻。
    明月清泉_e47b阅读 245评论 8 12