大话设计模式之工厂模式 C#
学无止境,精益求精
十年河东,十年河西,莫欺少年穷
学历代表你的过去,能力代表你的现在,学习代表你的将来
大话设计模式一书中第一个开讲的设计模式是简单工厂模式,关于简单工厂模式大家可参考鄙人的博客:代码无错就是优?简单工厂模式 C#
当然,本篇博客所讲的工厂模式和简单工厂模式还是非常类似的,因此,在进行工厂模式讲解之前,我们有必要重温下简单工厂模式
何为工厂模式?不论是简单工厂模式还是本篇的工厂模式,其工厂类主要负责生产对象,然后通过相应的对象调用相关的方法
在重温简单工厂模式之前,我们再次看下简单工厂模式的UML类图
针对上述的简单工厂模式UML类图,我们得到如下叙述:
1、简单工厂类是和运算类是有关联的(实线加箭头代表关联),简单工厂类的主要功能是生产运算对象
2、运算类用斜体表示,说明运算类为抽象类,运算类有两个属性及一个返回值为 double 的方法
3、加减乘除类继承运算类并实现GetResult()方法。
针对上述三点叙述,我们可用如下代码来实现(如果你还看不懂UML类图,可以参考鄙人博客:UML类图应该怎么看?)
public class 简单工厂类
{
double NumberA, NumberB;
public 简单工厂类() { }
public 简单工厂类(double A, double B)
{
this.NumberA = A;
this.NumberB = B;
}
double Oper = new double();
public double Operate(string 符号)
{
switch (符号)
{
case "+": Oper = new 加法类().GetResult(NumberA, NumberB); break;
case "-": Oper = new 减法类().GetResult(NumberA, NumberB); break;
case "*": Oper = new 乘法类().GetResult(NumberA, NumberB); break;
case "/": Oper = new 除法类().GetResult(NumberA, NumberB); break;
}
return Oper;
}
} public abstract class 运算类
{
public abstract double GetResult(double NumberA, double NumberB);
} public class 加法类:运算类
{
public override double GetResult(double NumberA, double NumberB)
{
return NumberA + NumberB;
}
} public class 减法类 : 运算类
{
public override double GetResult(double NumberA, double NumberB)
{
return NumberA - NumberB;
}
} public class 乘法类 : 运算类
{
public override double GetResult(double NumberA, double NumberB)
{
return NumberA * NumberB;
}
} public class 除法类 : 运算类
{
public override double GetResult(double NumberA, double NumberB)
{
if (NumberB != )
return NumberA / NumberB;
else throw new Exception("被除数不能为零"); }
}
static void Main(string[] args)
{
double A = ;
double B = ;
string F = "/";
简单工厂类 M = new 简单工厂类(A,B);
double Result = M.Operate(F);
Console.WriteLine(Result);
Console.ReadKey();
}
上述代码是鄙人看着UML类图自己设计的,和博客:代码无错就是优?简单工厂模式 C# 中的设计代码并不一样!当然,这两种代码都准确的表达的简单工厂的理念。有兴趣的也可以看下 代码无错就是优?简单工厂模式 中的代码实现形式。
OK,上述就是简单工厂模式的代码设计方案!
但是简单工厂模式违反了设计模式的开闭原则,所以我们有必要对其进一步优化!
所谓开闭原则:
这个原则其实有两个特性,一个是说对于扩展是开放的,另一个是说,对于修改是封闭的(ASD原则)
如何优化呢?
工厂模式闪亮登场...
首先看下工厂模式关于加减乘除的UML类图
额,似乎复杂了很多!
不急,我们慢慢分析,然后再用代码实现!
1、运算工厂接口依赖运算类,加法工厂类依赖加法类,减法工厂类依赖减法类,乘法工厂类依赖乘法类,除法工厂类依赖除法类!(虚线加箭头代表依赖)
2、加减乘除工厂类继承运算工厂接口,加减成熟类继承运算类(三角加实线代表继承)
3、下方的M的N次方类和对应的工厂类是用来扩展的。
那么,分析了UML类图的信息,怎样用代码实现呢?
首先我们来创建左侧部分的五个类(运算类及加减乘除类),如下:
/// <summary>
/// 运算类
/// </summary>
public class Operation
{
public double NumberA, NumberB;
public virtual double GetResult()
{
return ;
}
} public class Add : Operation
{
public override double GetResult()
{
return NumberA + NumberB;
}
} public class Sub : Operation
{
public override double GetResult()
{
return NumberA - NumberB;
}
} public class Mul : Operation
{
public override double GetResult()
{
return NumberA * NumberB;
}
} public class Div : Operation
{
public override double GetResult()
{
if (NumberB == )
throw new Exception("被除数不能为零");
return NumberA / NumberB;
}
}
其次,我们来构建右侧部分的一个接口及四个类(加减乘除工厂类),如下:
public interface IFactory
{
Operation GetOperation();
} public class AddFactory : IFactory
{
public Operation GetOperation()
{
return new Add();
}
} public class SubFactory : IFactory
{
public Operation GetOperation()
{
return new Sub();
}
} public class MulFactory : IFactory
{
public Operation GetOperation()
{
return new Mul();
}
} public class DivFactory : IFactory
{
public Operation GetOperation()
{
return new Div();
}
}
客户端代码为:
static void Main(string[] args)
{
IFactory F = new AddFactory();
Operation AM = F.GetOperation();
AM.NumberA = ;
AM.NumberB = ;
double sum = AM.GetResult();
Console.WriteLine(sum);
Console.ReadKey();
}
最后,我们来运行一下(7+8=15):
写到这儿,我可以自豪的说:如果你要加平方根运算,我只需新增平方根类及平方根工厂。因此,现在的设计是不违反设计模式的开闭规则的!
我们知道,在简单工厂模式中,我们可以通过运工厂类的 Switch Case 来判断具体的运算类型,但是上述所写的工厂模式却做不到了!这样写无形中加重了客户端的负担(客户端必须自己来判断运算类型),因此:有没有好的办法解决这个弊端呢?
答案是有,而且还有一个有趣的名字,叫:雷锋工厂
如何用代码实现呢?
@陈卧龙的博客
最新文章
- Codeforces Round #363 (Div. 2)
- Elasticsearch5.0.1索引压测结果
- spring web MVC
- 异步-学习笔记3 Task
- Spring小练习之宝宝淘项目
- 夺命雷公狗---DEDECMS----1dedecms的安装过程
- Python行和缩进
- Cstring类
- Comprehensive learning path – Data Science in Python深入学习路径-使用python数据中学习
- Cookie 添加,读取,删除
- 一步一步学python(三) - 使用字符串
- rsync远程数据同步工具的使用
- ios判断手机号是否可用
- android onSaveInstanceState应用实例
- Ubuntu 16.04 安装垃圾清理工具 BleachBit
- php中curl返回false的解决办法
- 关于H5页面的测试总结与分析
- 从.Net到Java学习第一篇——开篇
- 去中心化存储项目终极指南 | Filecoin, Storj 和 PPIO 项目异同
- linux 网络之 bond 网卡模式
热门文章
- 泛化之美--C++11可变模版参数的妙用
- [Linux.NET]Nginx 泛解析配置请求映射到多端口实现二级域名访问
- WebStorm连接Github教程
- [20180713]关于hash join 测试中一个疑问.txt
- 用Python实现数据结构之链表
- Navicat连接Oracle的几个问题及解决方案
- Java设计模式之一 ----- 单例模式
- 【Nginx】什么是Nginx?为什么使用Nginx?
- 2017-2018-2 20155314《网络对抗技术》Exp4 恶意代码分析
- Java中static、final、static final的区别【转】