开放封闭原则(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(开放封闭)原则的阐述的更多相关文章

  1. 必须知道的Spring Boot中的一些Controller注解

    这篇文章是抄其他人的,原址:https://cloud.tencent.com/developer/article/1082720 本文旨在向你介绍在Spring Boot中controller中最基 ...

  2. [你必须知道的.NET]第二十六回:认识元数据和IL(下)

    发布日期:2009.03.04 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 书接上回: 第二十四回:认识元数据和IL(上), ...

  3. MVC中你必须知道的13个扩展点

    MVC中你必须知道的13个扩展点 pasting 转:http://www.cnblogs.com/kirinboy/archive/2009/06/01/13-asp-net-mvc-extensi ...

  4. 解惑《你必须知道的.net》——C#继承关系中【方发表】的创建和调用

    前言: 现在正在读<你必须知道的.net>(第二版)一书,看到IL语言那一章,将call.callvirt和calli时候,书中举了一个例子,是一个三层继承的例子,我一开始看的时候就有点懵 ...

  5. [你必须知道的.NET]第二十五回:认识元数据和IL(中)

    发布日期:2009.02.25 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 书接上回[第二十四回:认识元数据和IL(上)], ...

  6. 每个项目中,你必须知道的11个Java第三方类库。

    Java第三方library ecosystem是一个很广阔的范畴.不久前有人撰文:每个项目中,你必须知道的11个Java第三方类库. 单元测试 1.DBUnit DBunit是一个基于junit扩展 ...

  7. [你必须知道的.NET]第三十回:.NET十年(下)

    发布日期:2009.05.11 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文部分内容,已 ...

  8. [你必须知道的.NET]第二十九回:.NET十年(上)

    发布日期:2009.05.08 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文部分内容,已 ...

  9. 从零开始学习jQuery(剧场版) 你必须知道的javascript

    原文:从零开始学习jQuery(剧场版) 你必须知道的javascript 一.摘要 本文是jQuery系列教程的剧场版, 即和jQuery这条主线无关, 主要介绍大家平时会忽略的一些javascri ...

随机推荐

  1. 【openGL】画五角星

    #include "stdafx.h" #include <GL/glut.h> #include <stdlib.h> #include <math ...

  2. 玩玩Excel下的Power View

    作为微软平台下的数据展示工具,Power View是一个不错的选择.而在Excel 2013下,即使你没有SharePoint的实例那么你也可以玩转它.此篇讲对Excel 2013下的Power Vi ...

  3. maven错误解决一:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.5.1:compile (default-compile)

    解决方法是将 jre的目录在 window->Preferences 里修改java installed里的jre目录改为jdk目录即可. 原因是在jre目录下不存在tools.jar.

  4. Go1.7改善了编译速度并且会生成更快的代码

    Go1.7的开发周期正在接近它的下一个里程碑,Go的提交者Dave Cheney报告了子即将发布的版本中,团队成员在语言工具链上的努力. Cheney称,基于当前的开发状态,Go1.7将会很容易就成为 ...

  5. Linux文本比较-diff&awk

    最近为了完成工作,需要将两个文件A.old和A进行比较,然后将A中新增加的部分保存到A中,其他部分删除.经过查找相关资料,发现有两种比较好的方法. 1. 使用diff命令 diff old.file ...

  6. 64位ubuntu下重新编译hadoop2.2流水账

    hadoop官方网站中只提供了32位的hadoop-2.2.0.tar.gz,如果要在64位ubuntu下部署hadoop-2.2.0,就需要重新编译源码包,生成64位的部署包.建议以下操作使用roo ...

  7. sp_executesql的用法

    之前做项目的时候负责一个成绩分析的模块儿,写存储过程的时候因为考试的科目是不固定的,所以导致查找成绩的sql语句也是动态的,就用到了sp_executesql,下面就来说一说它的用法 需求:表名是动态 ...

  8. barabasilab-networkScience学习笔记2-图理论

    第一次接触复杂性科学是在一本叫think complexity的书上,Allen博士很好的讲述了数据结构与复杂性科学,barabasi是一个知名的复杂性网络科学家,barabasilab则是他所主导的 ...

  9. SQLServer 维护脚本分享(04)服务器角色和数据库角色相关操作

    /*------------------------------------------------------------------------------------ [服务器级别-服务器角色] ...

  10. poj 2115 Looooops

    C Looooops Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 23637   Accepted: 6528 Descr ...