一、工厂设计模式
1.引入
(1) 原始社会时,劳动社会基本没有分工,需要斧子的人(调用者)只好自己去磨一把斧子,每个人拥有自己的斧子,如果把大家的石斧改为铁斧,需要每个人都要学会磨铁斧的本领,工作效率极低。
(2) 工业社会时,工厂出现,斧子不再由普通人完成,而由工厂生产,当人们需要斧子的时候,可以到工厂购买斧子,无需关心斧子是怎么制造出来的,如果废弃铁斧为钢斧,只需改变工厂的制造工艺即可,制作工艺是工厂决定的,工厂生产什么斧子,工人们就得用什么斧子。
(3)近代工业社会,工厂蓬勃发展,人们需要什么斧子,只需要提供一个斧子图形,商家会按照你提供的图形将你的斧子订做好,送上门。
2.说明
工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A(). 工厂模式也是用来创建实例对象的,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。
3.适用
在以下情况下应当考虑使用抽象工厂模式:
(1) 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
(2) 这个系统有多于一个的产品族,而系统只消费其中某一产品族。
(3) 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
(4) 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
小练习:工厂模式实现计算器
public class Operation
{
private double _numberA = 0;
private double _numberB = 0;
public double NumberA
{
get { return _numberA; }
set { _numberA = value; }
}
public double NumberB
{
get { return _numberB; }
set { _numberB = value; }
}
public virtual double GetResult()
{
double result = 0;
return result;
}
}
//加法运算类,继承于运算类
class OperationAdd : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA + NumberB;
return result;
}
}
//减法运算类,继承于运算类
class OperationSub : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA - NumberB;
return result;
}
}
//乘法运算类,继承于运算类
class OperationMul : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA * NumberB;
return result;
}
}
//除法运算类,继承与运算类
class OperationDiv : Operation
{
public override double GetResult()
{
double result = 0;
if (NumberB == 0)
throw new Exception("除数不能为0!");
result = NumberA / NumberB;
return result;
}
}
//简单运算工厂类
public class OperationFactory
{
public static Operation createOperate(string operate)
{
Operation oper = null;
switch (operate)
{
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
}
class Program
{
static void Main(string[] args)
{
Operation oper;
Console.WriteLine("");
Console.Write("请输入数字A:");
string strNumberA = Console.ReadLine();
Console.Write("请选择运算符号(+、-、*、/):");
string strOperate = Console.ReadLine();
Console.Write("请输入数字B:");
string strNumberB = Console.ReadLine();
//只需输入运算符号,工厂就实例化出合适的对象
oper = OperationFactory.createOperate(strOperate);
oper.NumberA = Convert.ToDouble(strNumberA);
oper.NumberB = Convert.ToDouble(strNumberB);
double result = oper.GetResult();
Console.WriteLine("运算结果为:"+ strNumberA +" "+ strOperate +" "+ strNumberB +" = " + result);
Console.ReadKey();
}
}
二、策略模式
1.说明
(1) 定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户。
(2) 是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
2.适用
策略模式就是用来封装算法的,但在实践中间,我们发现可用它封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式来处理这种变化的可能性。
3.优点
(1) 策略模式的Strate类层次为Context定义了一些列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能。
(2) 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
三、单一职责原则
1.说明
(1) 就一个类而言,应该仅有一个引起它变化的原因。
(2) 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。
(3) 软件设计真正要做的许多内容,就是发现职责并把那些职责相互分离
四、开放--封闭原则
1.说明
(1) "开放-封闭"原则要求系统对扩展开放,对修改封闭。通过扩展达到增强其功能的目的。
(2) 开放-封闭原则是面向对象设计的核心所在。开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象,然而对应用程序中的每个部分刻意地进行抽象同样不是一个号主意。
五、依赖倒转原则
1.说明
(1) 抽象不应该依赖细节,细节应该依赖于抽象
(2) 高层模块不应该依赖低层模块。两个都应该依赖抽象
(3) 依赖倒转其实可以说是面向对象设计的标志,用哪种语言来编写程序不重要,如果编写时考虑的都是如果针对抽象编程而不是针对细节编程,即程序中所有的依赖关系都是终止于抽象类或者接口,那就是面向对象的设计,反之那就是过程化的是设计。
2.里氏代换原则
(1) 一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且察觉不出父类对象和子类对象的区别。也就是说,在软件里面,把父类都替换成它的子类,程序行为没有变化。