面向对象的设计原则_开闭原则

动机

一个设计良好的应用程序应该充分考虑到开发和维护阶段需求的频繁变化,通常情况下,添加一个新的功能需要做出很多修改,我们应该使对已有代码的修改最小化,因为他们已经经过了测试。对现有代码做出修改将会以一种不可预料的方式影响它们的已有功能。

 

开放-关闭原则 (以下简称开闭原则)

开-闭原则:

一个软件实体应该对扩展开发,对修改关闭。

 

开闭原则是说我们应该努力设计不需要修改的模块。在扩展系统的行为时,我们只需要添加新的代码,而不需要修改已有的代码。一般可以通过添加新的子类和重写父类的方法来实现。

 

满足开闭原则的模块符合下面两个标准:

  • 对扩展开放 ------- 模块的行为可以被扩展从而满足新的需求。
  • 对修改关闭 ------- 不允许修改模块的源代码。(或者尽量使修改最小化)

这两个标准看似相互矛盾的,那么我们怎么实现他们呢?

怎样实现开闭原则

  • 抽象
  • 多态
  • 继承
  • 接口

要想使一个软件系统的所有模块都满足开闭原则是不太现实的,不过我们应该努力使大部分模块满足开闭原则。开闭原则是面向对象设计的核心,满足该原则可以达到最大限度的复用和可维护性。

 


实例

考虑下面某个类的方法:

 

Java代码 复制代码  收藏代码
  1. public double totalPrice(Part[] parts) {   
  2. double total = 0.0;   
  3. for (int i=0; i<parts.length; i++) {   
  4. total += parts[i].getPrice();   
  5. }   
  6. return total;   
  7. }  
public double totalPrice(Part[] parts) {
double total = 0.0;
for (int i=0; i<parts.length; i++) {
total += parts[i].getPrice();
}
return total;
}

 

上面函数的功能是计算给定的零件数组中所有零件价格的总和,如果Part是一个基类或者接口,那我们就可以利用多态的特性,当有新的零件被添加进来时不需要修改该函数的代码。这样它就可以满足开闭原则。

 

但是如果我们的会计部门规定当计算主板和内存的价格时,需要添加一些额外的费用,请看下面的代码:

Java代码 复制代码  收藏代码
  1. public double totalPrice(Part[] parts) {   
  2. double total = 0.0;   
  3. for (int i=0; i<parts.length; i++) {   
  4. if (parts[i] instanceof Motherboard)   
  5. total += (1.45 * parts[i].getPrice());   
  6. else if (parts[i] instanceof Memory)   
  7. total += (1.27 * parts[i].getPrice());   
  8. else  
  9. total += parts[i].getPrice();   
  10. }   
  11. return total;   
  12. }  
public double totalPrice(Part[] parts) {
double total = 0.0;
for (int i=0; i<parts.length; i++) {
if (parts[i] instanceof Motherboard)
total += (1.45 * parts[i].getPrice());
else if (parts[i] instanceof Memory)
total += (1.27 * parts[i].getPrice());
else
total += parts[i].getPrice();
}
return total;
}

 

 

现在它还符合开闭原则吗?不!每次会计部门发布一个新的价格政策时,我们都需要修改totalPrice()方法!它对修改不是关闭的,显然,价格政策的改变意味着我们必须修改某处的代码,那么我们应该怎么做呢?为了使用我们第一个版本的totalPrice()方法,我们需要把Part的getPrice()方法的价格政策包含进来。

下面是Part和ConcretePrat类:

Java代码 复制代码  收藏代码
  1. // Class Part is the superclass for all parts.   
  2. public class Part {   
  3. private double price;   
  4. public Part(double price) (this.price = price;}   
  5. public void setPrice(double price) {this.price = price;}   
  6. public double getPrice() {return price;}   
  7. }   
  8. // Class ConcretePart implements a part for sale.   
  9. // Pricing policy explicit here!   
  10. public class ConcretePart extends Part {   
  11. public double getPrice() {   
  12. // return (1.45 * price); //Premium   
  13. return (0.90 * price); //Labor Day Sale   
  14. }   
  15. }  
// Class Part is the superclass for all parts.
public class Part {
private double price;
public Part(double price) (this.price = price;}
public void setPrice(double price) {this.price = price;}
public double getPrice() {return price;}
}
// Class ConcretePart implements a part for sale.
// Pricing policy explicit here!
public class ConcretePart extends Part {
public double getPrice() {
// return (1.45 * price); //Premium
return (0.90 * price); //Labor Day Sale
}
}

 

但是,现在如果价格政策改变,我们必须修改Part的子类,一个更好的方法是建立一个PricePolicy类,它可以为我们提供不同的价格政策:

Java代码 复制代码  收藏代码
  1. /**  
  2. * Class PricePolicy implements a given price policy.  
  3. */  
  4. public class PricePolicy {   
  5. private double factor;   
  6. public PricePolicy (double factor) {   
  7. this.factor = factor;   
  8. }   
  9. public double getPrice(double price) {return price * factor;}   
  10. }  
/**
* Class PricePolicy implements a given price policy.
*/
public class PricePolicy {
private double factor;
public PricePolicy (double factor) {
this.factor = factor;
}
public double getPrice(double price) {return price * factor;}
}

 

使用这种方法,我们可以在运行时动态的设置Part对象所引用的PricePoilcy对象,在实际的程序中,零件的价格和相关的PricePolicy可以从数据库中获取。

 

总结

像许多其他原则一样,开闭原则只是面向对象设计的一个原则,实现一个灵活的设计需要额外的时间和努力,引入新的抽象层会增加代码的复杂性。因此,该原则适用于那些需求会经常发生变化的系统。有许多设计模式可以帮助我们扩展功能而不需要修改代码。例如,装饰模式等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值