开闭原则
在面向对象编程领域中,开闭原则要求软件对象应该对扩展开放,对修改关闭。即,一个实体在不修改其原有代码的基础上,为其增添新的功能或改变其行为。
举个例子,现有一个砸金蛋的活动,顾客可以选择工具来砸开金蛋,获得奖励。我们为顾客准备了一把锤子,顾客使用锤子砸开金蛋,获得奖励。
首先,不使用设计模式以及开闭原则的方式来为其编码。
硬编码
- 定义锤子类,需要敲击三次才能砸开金蛋
//锤子工具
public class HammerTool {
private string toolName = "锤子";
private int count = 3;
//敲击
public void Rap () {
for (int i = 0; i < count; i++) {
Console.WriteLine (toolName + ":第{0}次", i);
}
}
}
- 定义顾客类,顾客使用工具砸开金蛋
//顾客
public class User {
private HammerTool _hammerTool;
public User (HammerTool hammerTool) {
_hammerTool = hammerTool;
}
//使用工具
public void UseTool () {
_hammerTool.Rap ();
}
}
- 客户端调用
class Program {
static void Main (string[] args) {
var user = new User (new HammerTool ());
user.UseTool ();
}
}
- 输出
锤子:第0次
锤子:第1次
锤子:第2次
好了,通过硬编码的砸金蛋活动完成了。过了几天,活动方反应,这个活动还不错,参与人数也挺多,现在他们需要增加一个工具———斧子,好吧,按照我们正常的逻辑,当然是去修改代码咯,这里还是使用硬编码实现。
硬编码——增加斧子
- 定义斧子类,只需要敲击一次就可以砸开金蛋
//斧子工具
public class HatChetTool {
private string toolName = "斧子";
private int count = 0;
public void Rap () {
Console.WriteLine (toolName + ":第{0}次", count);
}
}
- 原先的User类已经不适用于当前的斧子工具了,需要重新修改User类适应当前工具;好吧,很烦
public class NewUser{
private HatChetTool _hatChetTool;
public NewUser (HatChetTool hatChetTool) {
_hatChetTool = hatChetTool;
}
//使用工具
public void UseTool () {
_hatChetTool.Rap ();
}
}
- 客户端调用
static void Main (string[] args) {
User user=new User(new HammerTool());
user.UseTool();
NewUser newUser=new NewUser(new HatChetTool());
newUser.UseTool();
}
- 输出
锤子:第0次
锤子:第1次
锤子:第2次
斧子:第0次
任务终于完成了,可是总感觉哪里说不出来的不对劲,先休息吧。叮铃铃,叮铃铃,叮铃铃,叮铃铃,叮铃铃。 活动方来电话了,这个活动太火爆了,骗了不少老人和小孩的钱。现在还要再加几个工具。哎呦,难受。。。。算了,试试设计模式吧。
首先分析一下当前的需求,我们的目标是使用不同的工具砸开金蛋,各个工具的使用方式都不同,比如锤子要敲击三次,而斧子只需要敲击一次;活动方会时不时的增加不同的工具。那么,我们是不是可以把工具抽象出来,在客户端中使用抽象,而不是使用具体的工具类和客户端交互。
使用开闭原则
- 为所有的工具类定义一个接口
public interface IBaseTool {
void Rap ();
}
- 锤子工具
//锤子工具
public class HammerTool : IBaseTool {
private string toolName = "锤子";
private int count = 3;
public void Rap () {
for (int i = 0; i < count; i++) {
Console.WriteLine ("{0} : 第{1}次", toolName, i+1);
}
}
}
- 斧子工具
//斧子工具
public class HatChetTool : IBaseTool {
private string toolName = "斧子";
private int count = 1;
public void Rap () {
Console.WriteLine ("{0} : 第{1}次",toolName,count);
}
}
- 顾客类
//顾客
public class User {
private IBaseTool _baseTool;
public User (IBaseTool baseTool) {
_baseTool = baseTool;
}
public void UserTool () {
_baseTool.Rap ();
}
}
- 客户端调用
class Program {
static void Main (string[] args) {
User user_01 = new User (new HammerTool ());
user_01.UserTool ();
User user_02 = new User (new HatChetTool ());
user_02.UserTool ();
}
}
- 输出
锤子 : 第1次
锤子 : 第2次
锤子 : 第3次
斧子 : 第1次
完成,要休息了。呼呼呼…,呼呼呼…,呼呼呼…,呼呼呼…,呼呼呼…,呼呼呼…,呼呼呼…,呼呼呼…,呼呼呼…
叮铃铃…叮铃铃…叮铃铃…叮铃铃…叮铃铃…叮铃铃…叮铃铃…叮铃铃…叮铃铃…
活动方:现在老人和小孩学精明了,没那么好骗了,我们推出了一个新的工具————绣花针;要求,绣花针要戳一千次才能砸开金蛋。好吧,虽然满腹罪恶,心有不甘,还是闭着眼睛为活动方增加了这样的需求。
- 增加绣花针工具
public class EmbroideryNeedle : IBaseTool {
private string toolName = "绣花针";
private int count = 1000;
public void Rap () {
Console.WriteLine ("黑心无量活动方");
for (int i = 0; i < count; i++) {
Console.WriteLine ("{0} : 第{1}次", toolName, i + 1);
}
}
}
- 客户端调用
class Program {
static void Main (string[] args) {
User user_01 = new User (new HammerTool ());
user_01.UserTool ();
User user_02 = new User (new HatChetTool ());
user_02.UserTool ();
User user_03 = new User (new EmbroideryNeedle ());
user_03.UserTool ();
}
}
- 输出,太长了,自己控制台打去吧
总结:开闭原则,对扩展开放,对修改关闭。当有新的需求增加时,我们不对原有的代码做任何的修改,只增加新的需求,并在客户端增加对应的调用方式。