说到设计模式,其实无非就是对编程进行分装,多态,继承的综合运用,从而衍生到了那么多的设计模式,面向对象技术,就是为了让我们的程序更加的灵活,维护性更好,复用性更高。
比如说我国的四大发明,其中有一样就和我们的面向对象技术有异曲同工之妙——活字印刷术,他不在像人们的过程思维了,比如要印一篇《兰亭集序》,那么就刻一个《兰亭集序》的版,错一个字,整版废除,印完一般,整版再次废除,无意中加了太多的工作量。而用到了面向对象的活字印刷术,我把需要的字刻出来,要印什么文章,我就把模子找出来,不用的我收起来,没有的字我再刻一个,简单明了,以后再用,这样的话变实现了灵活性,复用性,可扩展性。这也正式为什么他可以和无中生有的纸,火药,指南针并列为四大发明。
今天我就为大家介绍几个运用面向对象技术的几个设计模式:简单工厂模式,工厂方法模式,抽象工厂模式。
简单工程模式
首先确定要实例化的对象,将来是否要增加实例,然后考虑一个单独的类来做这个创造实例的过程,这既是工厂。
那么就先为大家做一个简单的计算器的程序来了解什么叫做简单工厂模式。
UML图
代码
//具体的算之前,做一个运算的类
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 OperationPlus : Operation
{
public override double GetResult() //重写基类的方法
{
double result = 0;
result = NumberA + NumberB;
return result;
}
}
//定义减法类,继承了运算类
class OperationMinus : 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("除数不能为零");
result = NumberA / NumberB;
return result;
}
}
接下来便是工厂类
public class OperationFactory
{
public static Operation createOperate(string operate)
{
Operation oper = null;
switch (operate)
{
case "+":
oper = new OperationPlus();
break;
case "-":
oper = new OperationMinus();
break;
case "*":
oper = new OperationMul();
break ;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
static void Main(string[] args)
{
Operation oper;
oper = OperationFactory.createOperate("+");
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();
}
运用这个程序,如果我们要加一个算法,我们就可以再加一个算法类,然后再加一个case就可以了。
工厂方法模式
定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到子类。
我们还拿简单工程的例子来说明工厂方法模式,上面说到如果我要加一个开放的运算方法的话,我就要加一个开放的运算类,然后再去工厂类中增加一个case,最后去客户端修改代码,所以也就是说我要修改三个地方,虽然比面向过程的开发过程要方便了很多,但是还是违反了开放封闭原则,对于添加我们开发,对于修改我们封闭。
所以在简单工程的基础上,我们继续优化,于是出现了工厂方法模式。
UML图
代码
//运算类
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;
}
}
工厂方法实现,先创建一个接口
interface IFactory
{
Operation CreateOperation();
}
然后加减乘除各建一个具体的工厂去实现这个接口
//加法工厂
class AddFactory:IFactory
{
public Operation CreateOperation()
{
return new OperationAdd();
}
}
//减法工厂
class SubFactory : IFactory
{
public Operation CreateOperation()
{
return new OPerationSub();
}
}
//乘法工厂
class MulFactory : IFactory
{
public Operation CreateOperation()
{
return new OperationMul();
}
}
//除法工厂
class DivFactory : IFactory
{
public Operation CreateOperation()
{
return new OperationDiv();
}
}
客户端代码
IFactory operFactory = new AddFactory();
Operation oper = operFactory.CreateOperation(); //实例化算法
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();
简单工厂VS工厂方法
从代码我们可以发现,简单工厂模式最大的有点在于工厂类中包含了必要的逻辑,根据客户端的选择条件实例化相关的类,对客户来说,去除了与具体产品的依赖,就像上边的计算机,只需要把“+”给工厂,工厂自动就给出了相应的实例,客户端只要去做就可以。但是如果我们要加一个开方的功能,我们就要加一个case的分支条件语句,也就是修改了运来的代码,所以用工厂方法模式,把工厂类抽象出一个接口,接口只有一个方法,就是创建抽象产品的方法,然后让所有要生产具体类的工厂区实现这个接口,这样我们增加开方的功能时就不需要修改工厂类,值增加运算类和工厂类就可以了,实现了开放-封闭原则。
抽象工厂方法
提供一个创建一系列相关或者相互依赖对象的接口,而无需制定他们具体的类。UML图
代码
{
void Insert(User user);
User GetUser(int id);
}
interface IFactory
{
IUser CreateUser();
IDepartment CreateDepartment();
}
interface IDepartment
{
void Insert(Department department);
Department GetDepartment(int id);
}
//数据库访问
class User
{
private int _id;
public int ID
{
get { return _id; }
set { _id = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
class Department
{
private int _id;
public int ID
{
get { return _id; }
set { _id = value; }
}
private string deptName;
public string DeptName
{
get { return deptName; }
set { deptName = value; }
}
}
class SqlserverDepartment:IDepartment //用于访问SqlServer的department
{
public void Insert(Department department)
{
Console.WriteLine("在department表中添加一条记录");
}
public Department GetDepartment(int id)
{
Console.WriteLine("在sqlserver中根据ID查找department表中的一条记录");
return null;
}
}
//用于访问Access的department
class AccessDepartment : IDepartment
{
public void Insert(Department department)
{
Console.WriteLine("在department表中添加一条记录");
}
public Department GetDepartment(int id)
{
Console.WriteLine("在Access中根据ID查找department表中的一条记录");
return null;
}
}
//实例化sqlserverUser
class SqlServerFactory:IFactory
{
public IUser CreateUser()
{
return new SqlserverUser();
}
public IDepartment CreateDepartment()
{
return new SqlserverDepartment();
}
}
//实例化AccessUser
class AccessFactory : IFactory
{
public IUser CreateUser()
{
return new AccessUser();
}
public IDepartment CreateDepartment()
{
return new AccessDepartment();
}
}
客户端代码
User user = new User();
Department department = new Department();
IFactory factory = new SqlServerFactory();
IUser iu = factory.CreateUser();
iu.Insert(user);
iu.GetUser(1);
IDepartment id = factory.CreateDepartment();
id.Insert(department);
id.GetDepartment(2);
Console.Read();
结果如下
优缺点
抽象工厂最大的好处便是易于交换产品系列,由于具体工厂类,例如IFactory factory = new AccessFactory(),在一个应用中只需要在初始化的时候出现一次,这就使得一个应用的具体工厂变的非常容易,它之需要改变具体工厂即可使用不同的产品配置。第二它让具体的创建实例过程与客户分离,客户端是通过他们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。
而缺点也很明显,就是如果我们要增加一个功能,就需要修改多余一个的类,这是非常不好的。