此篇已收录至《你必须知道的.Net》读书笔记目录贴,点击访问该目录可以获取更多内容。
一、单一职责原则
(1)核心思想:一个类最好只做一件事,只有一个引起它变化的原因
(2)常用模式:Facade模式、Proxy模式
(3)基本方法:Extract Interface 抽取接口、Extract Class 抽取类、Extract Method 抽取方法
(4)DEMO:数据库管理系统中根据不同权限进行CRUD操作(这里是使用Proxy模式重构后的代码)
代码语言:javascript复制 public interface IDBAction
{
void Add();
bool Delete();
void View();
}
public class DBManager : IDBAction
{
public DBManager(string id)
{
}
public void Add()
{
//执行数据增加
Console.WriteLine("增加数据成功。");
}
public bool Delete()
{
//执行数据删除
return true;
}
public void View()
{
//执行数据查看
}
}
public class DBManagerProxy : IDBAction
{
private string id;
private IDBAction dbManager;
public DBManagerProxy(IDBAction dbAction)
{
dbManager = dbAction;
}
//处理权限判断的逻辑
public string GetPermission(string id)
{
return null;
//return "CanAdd";
}
public void Add()
{
if (GetPermission(id) == "CanAdd")
{
dbManager.Add();
}
}
public bool Delete()
{
if (GetPermission(id) == "CanDelete")
{
dbManager.Delete();
}
return true;
}
public void View()
{
if (GetPermission(id) == "View")
{
dbManager.View();
}
}
}
public class DBClient
{
public static void Main()
{
IDBAction DBManager = new DBManagerProxy(new DBManager("CanAdd"));
DBManager.Add();
}
}
(5)规则建议:
①一个类只有一个引起它变化的原因,否则就应当考虑重构;
②测试驱动开发,有助于实现合理分离功能的设计;
③可以通过Facade模式或Proxy模式进行职责分离;
二、开放封闭原则
(1)核心思想:软件实体应该是可扩展的,而不可修改的-->即对扩展开放,对修改封闭。在面向对象的编程中,即对抽象编程,而不对具体编程。
(2)常用模式:Template Method模式、Strategy模式
(3)DEMO:银行窗口业务办理场景
代码语言:javascript复制 class Client
{
private string ClientType;
public Client(string clientType)
{
ClientType = clientType;
}
public IBankProcess CreateProcess()
{
//实际的处理
switch (ClientType)
{
case "存款用户":
return new DepositProcess();
break;
case "转帐用户":
return new TransferProcess();
break;
case "取款用户":
return new DrawMoneyProcess();
break;
}
return null;
}
}
interface IBankProcess
{
void Process();
}
//按银行按业务进行分类
class DepositProcess : IBankProcess
{
public void Process()
{
//办理存款业务
Console.WriteLine("处理存款。");
}
}
class TransferProcess : IBankProcess
{
public void Process()
{
//办理转帐业务
Console.WriteLine("处理转帐。");
}
}
class DrawMoneyProcess : IBankProcess
{
public void Process()
{
//办理取款业务
}
}
class FundProcess : IBankProcess
{
public void Process()
{
//办理基金业务
}
}
class EasyBankStaff
{
private IBankProcess bankProc = null;
public void HandleProcess(Client client)
{
//业务处理
bankProc = client.CreateProcess();
bankProc.Process();
}
}
class BankProcess
{
public static void Main()
{
EasyBankStaff bankStaff = new EasyBankStaff();
bankStaff.HandleProcess(new Client("转帐用户"));
}
}
(4)规则建议:
①Liskov替换原则和合成/聚合复用原则为OCP实现提供保证;
②可以通过Template Method和Strategy模式进行重构;
③封装变化是实现OCP的重要手段;
三、依赖倒置原则
(1)核心思想:依赖于抽象-->抽象不应该依赖于具体,具体应该依赖于抽象;
(2)基本方法:在依赖之间定义一个抽象的接口,高层模块调用接口的方法,低层模块实现接口的定义;
(3)DEMO:银行窗口不同业务客户场景
代码语言:javascript复制 interface IClient
{
IBankProcess CreateProcess();
}
class DepositClient : IClient
{
IBankProcess IClient.CreateProcess()
{
return new DepositProcess();
}
}
class TransferClient : IClient
{
IBankProcess IClient.CreateProcess()
{
return new TransferProcess();
}
}
class DrawMoneyClient : IClient
{
IBankProcess IClient.CreateProcess()
{
return new DrawMoneyProcess();
}
}
class FundClient : IClient
{
IBankProcess IClient.CreateProcess()
{
return new FundProcess();
}
}
interface IBankProcess
{
void Process();
}
//按银行按业务进行分类
class DepositProcess : IBankProcess
{
public void Process()
{
//办理存款业务
Console.WriteLine("处理存款。");
}
}
class TransferProcess : IBankProcess
{
public void Process()
{
//办理转帐业务
Console.WriteLine("处理转帐。");
}
}
class DrawMoneyProcess : IBankProcess
{
public void Process()
{
//办理取款业务
}
}
class FundProcess : IBankProcess
{
public void Process()
{
//办理基金业务
}
}
class EasyBankStaff
{
private IBankProcess bankProc = null;
public void HandleProcess(IClient client)
{
//业务处理
bankProc = client.CreateProcess();
bankProc.Process();
}
}
class BankProcess
{
public static void Main()//Main_2_4_1
{
EasyBankStaff bankStaff = new EasyBankStaff();
bankStaff.HandleProcess(new TransferClient());
}
}
(4)规则建议:
①必须权衡在抽象和具体之间的取舍,方法不是一成不变的;
②依赖于抽象就是要对接口编程,不要对实现编程;
四、接口隔离原则
(1)核心思想:使用多个小的专门的接口,而不使用一个大的总接口;接口应该是内聚的,应该避免出现“胖”接口;不要强迫依赖不用的方法,这是一种接口污染;
(2)基本方法:委托分离与多重继承分离(推荐)
(3)DEMO:不同年龄段人士使用电脑场景
代码语言:javascript复制 interface IComputerLearn
{
void ToLearn();
}
interface IComputerWork
{
void ToWork();
}
interface IComputerBeFun
{
void ToBeFun();
}
class Adult
{
private IComputerLearn myLearn;
private IComputerWork myWork;
private IComputerBeFun myFun;
public void UseComputer()
{
//主要是工作
myWork.ToWork();
//还可以娱乐
myFun.ToBeFun();
}
}
class Child
{
private IComputerLearn myLearn;
public void UseComputer()
{
//只有学习,不会依赖其他的方法
myLearn.ToLearn();
}
}
(4)规则建议:
①将功能相近的接口合并,可能造成接口污染;
②接口隔离能够保证系统扩展和修改的影响不会扩展到系统其他部分;
五、Liskov替换原则
(1)核心思想:子类必须能够替换其基类
(2)DEMO:父类提供虚函数,子类覆写虚函数
代码语言:javascript复制 class FatherClass
{
public virtual void Method()
{
//父类的行为
Console.WriteLine("Father Method.");
}
}
class SonClass : FatherClass
{
public override void Method()
{
//子类的行为
Console.WriteLine("Son Method.");
}
}
class GrandsonClass : SonClass
{
public override void Method()
{
Console.WriteLine("Grandson Method.");
}
}
class Test_LSP
{
public static void DoSomething(FatherClass f)
{
f.Method();
}
public static void Main_2_6_2()//Main_2_6_2
{
DoSomething(new SonClass());
SonClass son = new SonClass();
FatherClass father = son is FatherClass ? (FatherClass)son : null;
father.Method();
FatherClass f2 = new FatherClass();
SonClass son2 = f2 is SonClass ? (SonClass)f2 : null;
son2.Method();
}
}
(3)规则建议:
①违反了Liskov替换原则必然导致违反开放封闭原则;
②Liskov替换能够保证系统具有良好的扩展性;
③子类的异常必须控制在父类可以预计的范围,否则将导致替换违规;
本章思维导图
作者:周旭龙
出处:http://www.cnblogs.com/edisonchou/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。