我的博客原文:
开闭原则java
设计模式六大原则之六:开闭原则。git
姓名 :开闭原则github
英文名 :Open Closed Principle设计模式
价值观 :老顽童就是我,休想改变我框架
我的介绍 :ide
Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.(软件中的对象(类,模块,函数等等)应该对于扩展是开放的,可是对于修改是封闭的)
(来自维基百科)函数
停更了三四天了,这几天比较忙,不只仅是工做上,更可能是精神上。周日忽然老胃病又复发了,一直疼到凌晨 4,5 点。由于此次疼得蛮厉害的,因此准备去医院看一下医生,这时候才体验到大城市就医之苦。周日晚下载了微医 App (不是作广告哈),也不知道哪家医院好,在深圳两年半还没去过医院,随便选个三甲医院:北京大学深圳医院,看了消化内科门诊的医生列表,整整这一周主任医生都预定满了,顿时很崩溃,打电话给医院预定,最快只能预定 17 号,are you kidding?App 上有个 『当即问诊』功能,在线把情况告诉医生,医生一天以内接诊,须要花 60 块,我就尝试一下,没想到次日医生回复后,说能够下午去医院看,他能够临时加号。就这样跳过了预定,直接看病,不知道你是否也苦于看病烦,能够尝试这个方法,固然,若是你有更好的方法,能够留言让更多的人了解到。测试
跑题了跑题了,今天是想和你们分享设计模式最后一个原则:开闭原则。这个原则要求就是容许扩展,拒绝修改。既然上面讲到看医生,那就用一个跟看病有关的例子。this
小明去医院看病,医生开了阿司匹林药,小明去了收费台,付了钱,总共 20 块钱。例子的代码以下:debug
public class OcpTest { public static void main(String[] args) { Hospital hospital = new Hospital(); IPatient xiaoMing = new Patient("小明"); hospital.sellMedicine(xiaoMing); } } class Medicine { private String name; private BigDecimal price; public Medicine(String name, BigDecimal price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } } class Hospital { private Medicine medicine = new Medicine("阿司匹林", new BigDecimal(20)); public void sellMedicine(IPatient patient) { BigDecimal money = patient.pay(medicine); System.out.println(patient.getName() + " 花了 " + money.setScale(2, BigDecimal.ROUND_UP) + " 块钱买了药:" + medicine.getName()); } } interface IPatient { String getName(); BigDecimal pay(Medicine medicine); } class Patient implements IPatient{ private String name; public Patient(String name) { this.name = name; } @Override public BigDecimal pay(Medicine medicines) { return medicines.getPrice(); } @Override public String getName() { return name; } }
次日和朋友聚会聊起这事,小红说道:不对呀,前几天我在医院也拿了阿司匹林药,才 14 块钱呢。小花说:奇怪了,我买的是 16 块钱。小杰回应:怎么我买的是 18 块。怎么这药这么多个价格。小明 Google 搜了一下,发现价格跟社保有关,几我的便发现,原来他们都是“不一样人”:小明没有社保,小红社保是一档,小花社保是二挡,小杰社保是三挡。(假设社保一档打 7 折,社保二挡打 8 折,社保三挡打 9 折,虚拟的哈)
发现了这秘密后,做为和 IT 工做相关的人,便讨论起医院系统具体实现是怎么实现的。小红说:这很简单呢,药品给不一样人提供不一样的价格。代码以下:
class Medicine { private String name; private BigDecimal price; public Medicine(String name, BigDecimal price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public BigDecimal getPrice() { return price; } public BigDecimal getPrice1() { return price.multiply(new BigDecimal(0.7)); } public BigDecimal getPrice2() { return price.multiply(new BigDecimal(0.8)); } public BigDecimal getPrice3() { return price.multiply(new BigDecimal(0.9)); } public void setPrice(BigDecimal price) { this.price = price; } }
小花说:药片自己的价格是不会变的,只是给不一样人不一样价格,因此能够在病人获取价钱的时候去区分。代码以下:
class Patient implements IPatient{ private String name; private int level; public Patient(String name) { this.name = name; } @Override public BigDecimal pay(Medicine medicines) { if (level == 1) { return medicines.getPrice().multiply(new BigDecimal(0.7)); } else if (level == 2) { return medicines.getPrice().multiply(new BigDecimal(0.8)); } else if (level == 3) { return medicines.getPrice().multiply(new BigDecimal(0.9)); } return medicines.getPrice(); } @Override public String getName() { return name; } }
小杰陷入了沉思。。。
小明发话:大家说的方法均可以实现,可是总感受不对劲,若是之后有社保四挡,仍是要修改原来的代码,前 2 天设计模式老师讲的开闭原则忘记了么?里面说要对扩展开放,对修改封闭。我以为这个药片价格是由于咱们人而变的,那是否是咱们能够把没社保的归为一类人,一档社保的也为一类,以此类推。我以为这样实现更好,增长多 3 类病人,分别是一档社保、二挡社保、三挡社保。代码以下:
class OneLevelSocialSecurityPatient implements IPatient { private String name; public OneLevelSocialSecurityPatient(String name) { this.name = name; } @Override public BigDecimal pay(Medicine medicine) { return medicine.getPrice().multiply(new BigDecimal(0.7)); } @Override public String getName() { return this.name; } } class TwoLevelSocialSecurityPatient implements IPatient { private String name; public TwoLevelSocialSecurityPatient(String name) { this.name = name; } @Override public BigDecimal pay(Medicine medicine) { return medicine.getPrice().multiply(new BigDecimal("0.8")); } @Override public String getName() { return this.name; } } class ThreeLevelSocialSecurityPatient implements IPatient { private String name; public ThreeLevelSocialSecurityPatient(String name) { this.name = name; } @Override public BigDecimal pay(Medicine medicine) { return medicine.getPrice().multiply(new BigDecimal("0.9")); } @Override public String getName() { return this.name; } } // 测试代码 public static void main(String[] args) { Hospital hospital = new Hospital(); IPatient xiaoMing = new Patient("小明"); hospital.sellMedicine(xiaoMing); IPatient xiaoHong = new OneLevelSocialSecurityPatient("小红"); hospital.sellMedicine(xiaoHong); IPatient xiaoHua = new TwoLevelSocialSecurityPatient("小花"); hospital.sellMedicine(xiaoHua); IPatient xiaoJie = new ThreeLevelSocialSecurityPatient("小杰"); hospital.sellMedicine(xiaoJie); }
代码:
OcpTest.java
看了他们的对话和代码,是否是能知道哪一种方式更好了?对于小红来讲,她没理清价格变化的缘由,价格变化不在于药片;小花理清了,可是实现方式差了点,之后若是新增了四挡社保,她的实现要修改原有的代码,不符合开闭原则;小明的方法就符合开闭原则,若是新增四挡社保人员,他的方法只须要再额外扩展一个四挡社保人员就能够,不用动用其余代码。
用了这个你们可能不太喜欢的看病的场景来描述这个开闭原则,不要忌讳哈,但愿你们都健健康康,远离医院。
重申一下:对扩展开放,对修改封闭。若是有同窗常常看一些开源框架源码就会发现,有不少不少抽象类和接口,debug 进去很绕,其实这些抽象类和接口不少都是为了扩展用,由于做为开源框架,不得不实现各类可想象到的方案,而这些都基于开闭原则来实现的。之后有机会也能够写一下源码的文章分享给你们。
参考资料:《大话设计模式》、《Java设计模式》、《设计模式之禅》、《研磨设计模式》、《Head First 设计模式》
这周事情比较多,更新会不及时,周五还要出差去一趟上海,周六回深圳,周日回一趟老家,各类奔波。。。
但愿文章对您有所帮助,设计模式系列会持续更新,感兴趣的同窗能够关注公众号,第一时间获取文章推送阅读,也能够一块儿交流,交个朋友。