《你必须知道的.NET》书中对OCP(开放封闭)原则的阐述
开放封闭原则(OCP,Open Closed Principle)是面向对象原则的核心。由于软件设计本身所追求的墓边就是封装变化,降低耦合,而开放封闭原则就是对这一目标的直接体现。(你必须知道的.NET p48页)
以下用例子说明,同样来自该书。
假设在一个柜台业务处理系统,首先有客户:
public class Client
{
public string Name{get;set;}
private string ClientType { get; set; }
}
ClientType表示客户的类型,如"存款用户","转账用户","取款用户"
public class BusyBankStaff
{
private readonly BankProcess bankProcess = new BankProcess();
public void HandleProcess(Client client)
{
switch (client.ClientType)
{
case "存款用户":
bankProcess.Deposit();
break;
case "转账用户":
bankProcess.Transfer();
break;
case "取款用户":
bankProcess.DrawMoney();
break;
}
}
}
业务处理类
public class BankProcess
{
public void Deposit() { }
public void Transfer() { }
public void DrawMoney() { }
}
问题是,如果银行多了一种业务类型,比如代购公积金,那么,必然地,BankProcess要修改为
public class BankProcess
{
public void Deposit() { }
public void Transfer() { }
public void DrawMoney() { }
public void BuyFund(){}
}
,并且BusyBankStaff中坏味道的switch语句又要增加一个条件。
其实,这样类的设计违反了开放封闭原则。
所谓开放封闭,是指,对修改封闭——一个类一旦写好,就不能再修改;对扩展开放——如果有新的需求,可以在不修改原系统的基础上方便增加。
怎么改?抽象!对可能或经常变化的部分使用接口将其封装。在此例中,BusyBankStaff依赖于BankProcess类,将其改为依赖于一个IBankProcess接口
public interface IBankProcess
{
void Process();
}
然后,不同的业务类型都实现该接口
public class DepositProcess:IBankProcess
{
public void Process(){}
}
public class TransferProcess:IBankProcess
{
public void Process(){}
}
等等。
此时BusyBankStaff可以摇身一变,变成EasyBankStaff
public class EasyBankStaff
{
private readonly IBankProcess bankProcess = new BankProcess();
public void HandleProcess(Client client)
{
bankProcess=client.CreateProcess();
bankProcess.Process();
}
}
注意到,业务的分配由银行的业务员转为客户,让客户自己依据自己的类型创建相应的bankProcess对象——这就是现实中客户依据业务类型的不同在排队取号机前取不同的业务号码。
现在,若新增一个业务,只要增加一个实现IBankProcess接口的类即可。
如
public class BuyFund:IBankProcess
{
public void Process(){}
}
大功告成了吗?不!
若观察系统,我们会发现客户类此时已经转变为
public class Client
{
public string Name{get;set;}
private string ClientType { get; set; } public IBankProcess CreateProcess()
{
switch(clientType)
{
case"存款用户":
return new DepositProcess();
case "转账用户":
return new TransferProcess(); }
}
}
又是一个违反OCP的类,又是switch的坏味道。
怎么办?同样是抽象!
将client类抽象为接口
public interface IClient
{
IBankProcess CreateProcess();
}
然后不同类型的客户都实现这一接口
public class DepositClient:Client
{
IBankProcess CreateProcess
{
return new DepositProcess();
} }
public class TransferClient:Client
{
IBankProcess CreateProcess
{
return new TransferProcess();
} }
如果有新的客户类型,那么就新增一个这样的类即可。完成!
《你必须知道的.NET》书中对OCP(开放封闭)原则的阐述的更多相关文章
- 必须知道的Spring Boot中的一些Controller注解
这篇文章是抄其他人的,原址:https://cloud.tencent.com/developer/article/1082720 本文旨在向你介绍在Spring Boot中controller中最基 ...
- [你必须知道的.NET]第二十六回:认识元数据和IL(下)
发布日期:2009.03.04 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 书接上回: 第二十四回:认识元数据和IL(上), ...
- MVC中你必须知道的13个扩展点
MVC中你必须知道的13个扩展点 pasting 转:http://www.cnblogs.com/kirinboy/archive/2009/06/01/13-asp-net-mvc-extensi ...
- 解惑《你必须知道的.net》——C#继承关系中【方发表】的创建和调用
前言: 现在正在读<你必须知道的.net>(第二版)一书,看到IL语言那一章,将call.callvirt和calli时候,书中举了一个例子,是一个三层继承的例子,我一开始看的时候就有点懵 ...
- [你必须知道的.NET]第二十五回:认识元数据和IL(中)
发布日期:2009.02.25 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 书接上回[第二十四回:认识元数据和IL(上)], ...
- 每个项目中,你必须知道的11个Java第三方类库。
Java第三方library ecosystem是一个很广阔的范畴.不久前有人撰文:每个项目中,你必须知道的11个Java第三方类库. 单元测试 1.DBUnit DBunit是一个基于junit扩展 ...
- [你必须知道的.NET]第三十回:.NET十年(下)
发布日期:2009.05.11 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文部分内容,已 ...
- [你必须知道的.NET]第二十九回:.NET十年(上)
发布日期:2009.05.08 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文部分内容,已 ...
- 从零开始学习jQuery(剧场版) 你必须知道的javascript
原文:从零开始学习jQuery(剧场版) 你必须知道的javascript 一.摘要 本文是jQuery系列教程的剧场版, 即和jQuery这条主线无关, 主要介绍大家平时会忽略的一些javascri ...
随机推荐
- Delphi编程建议遵守的规范1---缩进、各种语句的用法
在编程时候,尤其是在一个大的团队里面,遵守统一的编程规范是极其重要的.为所有的开发人员制定一个源代码书写标准,以及程序和文件的命名标准,使他们在编程时有一致的格式,这样,每个编程人员编写的代码能够被其 ...
- Linux环境下段错误的产生原因及调试方法小结
转载自http://www.cnblogs.com/panfeng412/archive/2011/11/06/2237857.html 最近在Linux环境下做C语言项目,由于是在一个原有项目基础之 ...
- PowerDesigner连接Oracle数据库生成数据模型【数据源连接方式】
1.进入操作系统的管理工具 2.选择ODBC数据源[32位或64位] 3.列表中是当前数据库已有的数据源,右侧点击添加按钮,添加适合自己的数据源 4.在列表中选择索要连接数据库的ODBC驱动[这里我要 ...
- 手机web页面制作时的注意事项
一.手机页面的标准头规范 字符编码使用utf-:指定页面手机内存缓存中的存储时间段 device-width:通知浏览器使用设备的宽度作为可视区的宽度 initial-scale - 初始的缩放比例 ...
- C#屏幕截图
今天通过C#来实现一个简单的屏幕截图功能.实现思路,获取鼠标按下去的位置和鼠标左键释放的位置,计算这个区域的宽度和高度.然后通过 Graphics.CopyFromScreen 方法便可以获取到屏幕截 ...
- Accelerating Matlab
Matlab is a very useful programming environment, but it also has many inefficiencies. You might thin ...
- Android中设定EditText的输入长度(转)
如何限定Android的Text中的输入长度呢? 方法一:可以在layout xml中加上属性android:maxLength 比如: <EditText android:id ...
- java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory 解决方案
缺少 commons-logging.jar
- 【HTML5 video】video标签的部分属性解析
转自:http://www.cnblogs.com/kiter/archive/2013/02/25/2932157.html 现在如果要在页面中使用video标签,需要考虑三种情况,支持Ogg Th ...
- 【js 方法】js 页面刷新location.reload和location.replace的区别 【转】
[转]:http://zccst.iteye.com/blog/2162658 reload 方法,该方法强迫浏览器刷新当前页面. 语法: location.reload([bForceGet]) 参 ...