面向对象设计原则
单一职责原则(SRP, Single Responsibility Principle)
定义
一个类,最好只做一件事,只有一个引起它变化的原因。
应用
数据库管理系统为例,通常情况下根据不同的权限进行数据增删改查。
比较坏的设计将判断用户权限和对数据的增删改查放在一个类,在遇到权限或对数据操作修改时都需要修改该类
public void Add()
{
if (GetPermission("userId")=="CanAdd")
{
Console.WriteLine("我有权限添加数据");
}
}
考虑单一责任原则,将权限判断和对数据操作分到不同的类,通过权限代理实现单一职责
public interface IDBAction
{
void Add();
}
public class DBManager: IDBAction
{
public void Add()
{
//执行数据增加
}
}
public class DBManagerProxy : IDBAction
{
private IDBAction dbManager;
public DBManagerProxy(IDBAction dbAction)
{
dbManager = dbAction;
}
public string GetPermission(string userId)
{
string userRole = string.Empty;
return userRole;
}
public void Add()
{
if (GetPermission("userId") == "CanAdd")
{
dbManager.Add();
}
}
}
开放封闭原则(OCP, Open Closed Principle)
定义
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开发的,而对修改是封闭的。
应用
这里实现个计算器,由客户端和计算端组成。设计应该尽量保证计算端的核心业务不修改。坏的代码无法对功能扩展
public class Client
{
private CalculatorProcess _calculator = new CalculatorProcess();
public int NumFirst { get; set; }
public int NumSecond { get; set; }
public int Use(string oper)
{
int ret = 0;
switch (oper)
{
case "+":
ret = _calculator.Add(this.NumFirst, this.NumSecond);
break;
case "-":
ret = _calculator.Sbu(this.NumFirst, this.NumSecond);
break;
default:
break;
}
return ret;
}
}
public class CalculatorProcess
{
public int Add(int a,int b)
{
return a + b;
}
public int Sbu(int a,int b)
{
return a - b;
}
}
对计算端扩展开放,添加乘法
public class Client
{
private ICalculatorProcess _calculator;
public int NumFirst { get; set; }
public int NumSecond { get; set; }
public int Use(string oper)
{
int ret = 0;
switch (oper)
{
case "+":
_calculator = new Add();
ret = _calculator.Operation(this.NumFirst, this.NumSecond);
break;
case "-":
_calculator = new Sub();
ret = _calculator.Operation(this.NumFirst, this.NumSecond);
break;
case "*":
_calculator = new Mul();
ret = _calculator.Operation(this.NumFirst, this.NumSecond);
break;
default:
break;
}
return ret;
}
}
public interface ICalculatorProcess
{
int Operation(int a, int b);
}
public class Add : ICalculatorProcess
{
public int Operation(int a, int b)
{
return a + b;
}
}
public class Sub : ICalculatorProcess
{
public int Operation(int a, int b)
{
return a - b;
}
}
public class Mul:ICalculatorProcess
{
public int Operation(int a, int b)
{
return a * b;
}
}
依赖倒置原则(DIP, Dependency Inversion Principle)
定义
- 高层模块不应该依赖于底层模块,二者都应该依赖于抽象。
- 抽象不应该依赖于具体,具体应该依赖于抽象。
应用
依赖倒置也是著名的好莱坞法则:不要调用我们,我们会调用你。在高层与低层间添加一抽象层(如上面的计算器)。
接口隔离原则(ISP, Interface Segregation Principle)
定义
使用多个小的专门的接口,而不要使用一个大的总接口。
一个类对另一个类的依赖应该建立在最小的接口上,不要强迫依赖不用的方法,这是一种接口污染。
应用
天鹅(Swan)即会游泳又会飞,但是鸭子只会游泳。
强迫鸭子飞
接口隔离,做到最小接口
Liskov替换原则(LSP, Liskov Substitution Principle)
定义
子类必须能够替换其基类。
应用
主要体现在父类方法应该为virtual
方法,子类重写父类方法,则子类完全可以替换父类在此调用自己的方法。