朝着理想坚实迈进
先前我们讨论了单一责任原则。 关于实体原则首字母缩写, 打开/关闭原则是该行中的第二个原则。
“软件实体(类,模块,功能等)应打开以进行扩展,但应关闭以进行修改”
通过采用该原理,目标是在不修改其源代码的情况下扩展模块的行为。
想象一下对我们的一种产品应用折扣的情况。 折扣服务将应用指定的折扣并返还折扣价。
目前,我们的系统只有一种折扣适用于所有成年人。
package com.gkatzioura.solid.ocp;import java.math.BigDecimal;
import java.math.RoundingMode;public class Discount {public BigDecimal apply(BigDecimal price) {BigDecimal percent = new BigDecimal("0.10");BigDecimal discount = price.multiply(percent);return price.subtract(discount.setScale(2, RoundingMode.HALF_UP));}
}
折扣服务应将此折扣应用于给出的价格。
package com.gkatzioura.solid.ocp;import java.math.BigDecimal;public class DiscountService {public BigDecimal applyDiscounts(BigDecimal price,Discount discount) {BigDecimal discountPrice = price.add(BigDecimal.ZERO);discountPrice = discount.apply(discountPrice);return discountPrice;}
}
但是,我们公司希望为老年人提供折扣,因此我们有老年人折扣。
package com.gkatzioura.solid.ocp;import java.math.BigDecimal;
import java.math.RoundingMode;public class SeniorDiscount {public BigDecimal apply(BigDecimal price) {BigDecimal percent = new BigDecimal("0.20");BigDecimal discount = price.multiply(percent);return price.subtract(discount.setScale(2, RoundingMode.HALF_UP));}
}
折扣服务使事情变得有些复杂,因为该服务必须同时应用成人折扣和老年人折扣。
package com.gkatzioura.solid.ocp;import java.math.BigDecimal;public class DiscountService {public BigDecimal applyDiscounts(BigDecimal price,Discount discount) {BigDecimal discountPrice = price.add(BigDecimal.ZERO);discountPrice = discount.apply(discountPrice);return discountPrice;}public BigDecimal applySeniorDiscount(BigDecimal price,SeniorDiscount discount) {BigDecimal discountPrice = price.add(BigDecimal.ZERO);discountPrice = discount.apply(discountPrice);return discountPrice;}}
通过这样做,我们修改了折扣服务源代码以扩展其行为。 同样,对于销售部门可能提出的每一种不同的折扣,折扣服务也会获得额外的方法。
为了遵循开放/封闭原则,我们将创建一个折扣界面。
package com.gkatzioura.solid.ocp;import java.math.BigDecimal;public interface Discount {BigDecimal apply(BigDecimal price);
}
默认折扣将重命名为AdultDiscount并实现折扣界面。
package com.gkatzioura.solid.ocp;import java.math.BigDecimal;
import java.math.RoundingMode;public class AdultDiscount implements Discount {@Overridepublic BigDecimal apply(BigDecimal price) {BigDecimal percent = new BigDecimal("0.10");BigDecimal discount = price.multiply(percent);return price.subtract(discount.setScale(2, RoundingMode.HALF_UP));}
}
SeniorDiscount也将实现Discount接口。
package com.gkatzioura.solid.ocp;import java.math.BigDecimal;
import java.math.RoundingMode;public class SeniorDiscount implements Discount {@Overridepublic BigDecimal apply(BigDecimal price) {BigDecimal percent = new BigDecimal("0.20");BigDecimal discount = price.multiply(percent);return price.subtract(discount.setScale(2, RoundingMode.HALF_UP));}
}
最后但并非最不重要的一点是,我们将对DiscountService进行重构,以便基于Discount接口应用折扣。
package com.gkatzioura.solid.ocp;import java.math.BigDecimal;public class DiscountService {public BigDecimal applyDiscounts(BigDecimal price,Discount[] discounts) {BigDecimal discountPrice = price.add(BigDecimal.ZERO);for(Discount discount:discounts) {discountPrice = discount.apply(discountPrice);}return discountPrice;}
}
通过这种方式,折扣服务将能够应用不同的折扣而无需更改其源代码。
可以对折扣应用相同的原理。
假设我们希望有一个基本折扣可以在应用折扣时额外应用。
package com.gkatzioura.solid.ocp;import java.math.BigDecimal;
import java.math.RoundingMode;public abstract class BasicDiscount implements Discount {@Overridepublic BigDecimal apply(BigDecimal price) {BigDecimal percent = new BigDecimal("0.01");BigDecimal discount = price.multiply(percent);return price.subtract(discount.setScale(2, RoundingMode.HALF_UP));}
}
通过扩展BasicDiscount类,我们可以在BasicDiscount的行为上获得更多折扣,并且还可以在不修改BasicDiscount源代码的情况下扩展此行为。
您可以在github上找到源代码。 下一个原理是liskov替换原理。
另外,我还编写了备忘单,其中包含有关扎实原则的摘要。
在链接中注册以接收它。
翻译自: https://www.javacodegeeks.com/2018/02/solid-principles-open-closed-principle.html
朝着理想坚实迈进