Java设计模式之开闭原则(Open-Closed Principle)

Software entities like classes, modules and functions should be open for extension but closed for modifications.
(一个软件实体如类,模块和函数应该对扩展开放,对修改关闭【不修改源代码的情况下对功能进行扩展】。)

举例说明什么是开闭原则,以手机销售为例。
1.手机实体类Phone

public class Phone {
	//手机品牌
	private String name;
	//销售价格
	private int price;
	//研发公司
	private String company;
	//通过构造函数传递手机信息
	public Phone(String name, int price,String company) {
		this.name = name;
		this.price = price;
		this.company = company;
	}
	public String getName() {
		return this.name;
	}

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

	public String getCompany() {
		return this.company;
	}
}

2.手机商店类测试PhoneStore

public class PhoneStore {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Phone phone = new Phone("华为mate30Pro", 6400, "华为");
		System.out.println(
				"手机品牌:"+ phone.getName()+				
				"\n销售价格:"+ phone.getPrice()+
				"元\n研发公司:"+ phone.getCompany()
				);	
				
	}
}

测试运行结果

手机品牌:华为mate30Pro
销售价格:6400元
研发公司:华为

商店投入使用后,手机正常销售,但是今年遇到新冠肺炎疫情,经济下滑,实体店为了生存,需要打折来销售手机(价格大于5k,打8折,否则打9折),我们要如何应对这样一个需求变化呢?

在不修改源代码的情况下,我们新增一个子类DiscountPhone继承父类重写getPrice()方法。通过扩展实现变化,完成业务变化对系统的最小化开发,风险也小。

public class DiscountPhone extends Phone{
		 
	   public DiscountPhone(String name,int price,String company){
	      super(name, price, company);
	   }
	      
	    //重写价格方法:价格大于5k,打8折,否则打9折
	   public int getPrice(){
		   int originalPrice = super.getPrice();
		   int discountPrice = 0;
	       if(originalPrice > 5000){ 
	    	   discountPrice = originalPrice * 80 / 100;
	       }else{
	    	   discountPrice = originalPrice * 90 / 100;
	       }
		   return discountPrice;   
	   }
}

测试时可以直接将实例化Phone改成DiscountPhone

DiscountPhone phone = new DiscountPhone("华为mate30Pro", 6400, "华为");

这里作者多增几个手机品牌

import java.util.ArrayList;

public class PhoneStore {

	private final static ArrayList<Phone> phoneList = new ArrayList<Phone>();
	static {
		phoneList.add(new DiscountPhone("iPhone11", 4600, "Apple Inc."));
		phoneList.add(new DiscountPhone("华为mate30Pro", 6400, "华为技术有限公司"));
		phoneList.add(new DiscountPhone("小米10Pro", 5000, "北京小米科技有限责任公司"));
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		for(Phone phone:phoneList) {
			System.out.println(
			"手机品牌:"+ phone.getName() +
			"\n销售价格:"+ phone.getPrice() +
			"元\n研发公司:"+ phone.getCompany() +"\n"
			);
		}

再次测试运行结果

手机品牌:iPhone11
销售价格:4140元
研发公司:Apple Inc.

手机品牌:华为mate30Pro
销售价格:5120元
研发公司:华为技术有限公司

手机品牌:小米10Pro
销售价格:4500元
研发公司:北京小米科技有限责任公司

为什么要使用开闭原则?

  1. 开闭原则对测试的影响
    所有已经投产的代码都是有意义的, 并且都受系统规则的约束, 这样的代码都要经过“千锤百炼”的测试过程, 不仅保证逻辑是正确的,还要保证苛刻条件(高压力、 异常、 错误) 下不产生“有毒代码”(Poisonous Code) , 因此有变化提出时,我们就需要考虑一下,原有的健壮代码是否可以不修改, 仅仅通过扩展实现变化呢? 否则, 就需要把原有的测试过程回笼一遍, 需要进行单元测试、功能测试、 集成测试甚至是验收测试, 现在虽然在大力提倡自动化测试工具, 但是仍然代替不了人工的测试工作。

  2. 开闭原则可以提高复用性
    在面向对象的设计中, 所有的逻辑都是从原子逻辑组合而来的, 而不是在一个类中独立实现一个业务逻辑。 只有这样代码才可以复用,粒度越小,被复用的可能性就越大。 那为什么要复用呢? 减少代码量, 避免相同的逻辑分散在多个角落,避免日后的维护人员为了修改一个微小的缺陷或增加新功能而要在整个项目中到处查找相关的代码, 然后发出对开发人员“极度失望”的感慨。 那怎么才能提高复用率呢? 缩小逻辑粒度, 直到一个逻辑不可再拆分为止。

  3. 开闭原则可以提高可维护性
    一款软件投产后, 维护人员的工作不仅仅是对数据进行维护, 还可能要对程序进行扩展, 维护人员最乐意做的事情就是扩展一个类,而不是修改一个类, 甭管原有的代码写得多么优秀还是多么糟糕, 让维护人员读懂原有的代码, 然后再修改, 是一件很痛苦的事情,不要让他在原有的代码海洋里游弋完毕后再修改, 那是对维护人员的一种折磨和摧残。

  4. 面向对象开发的要求
    万物皆对象, 我们需要把所有的事物都抽象成对象, 然后针对对象进行操作, 但是万物皆运动, 有运动就有变化, 有变化就要有策略去应对,怎么快速应对呢? 这就需要在设计之初考虑到所有可能变化的因素, 然后留下接口, 等待“可能”转变为“现实”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值