C#设计模式之【创建型设计模式:工厂模式】
一. 简单工厂(非设计模式)
首先,严格上来说,简单工厂并非23种设计模式之一,但是还是有必要介绍一下,
现实中的工厂负责生产产品,编程中的简单工厂就是一个生产对象的类,它的主要功能就是负责创建类的实例。我们以一个生产汽车为例来分析简单工厂的作用:
注意:例子中的抽象类都可以用接口代替
代码如下:
/// <summary>
/// 汽车抽象类
/// </summary>
public abstract class Car
{
public abstract void CreateCar();
}
/// <summary>
/// 奥迪
/// </summary>
public class Audi : Car
{
public override void CreateCar()
{
Console.WriteLine("制造奥迪车");
}
}
/// <summary>
/// 宝马
/// </summary>
public class BMW : Car
{
public override void CreateCar()
{
Console.WriteLine("制造宝马车");
}
}
控制台代码:
Car car1 = new Audi(); //创建奥迪对象
Car car2 = new BMW(); //创建宝马对象
car1.CreateCar();
car2.CreateCar();
Console.Read();
输出结果:
这么一看,每次想要创建奥迪对象的时候,就去new Audi();想要创建宝马对象的时候,就 new BMW();嗯,挺好,没什么大问题。但是,当项目做大了以后,假设我有500个地方new BMW()。突然!由于项目需求的变更,宝马需要全部换成奥迪,这就难受了,得去找到500个创建宝马的地方修改代码。。。岂不是头皮发麻?
所以我们需要创建一个类来帮助我们创建对象,我们可以这么搞:
/// <summary>
/// 简单工厂:创建对象的地方
/// </summary>
public class CarFactory
{
private Car car = null;
public Car CreateCarType(string carType)
{
switch (carType)
{
case "Audi":
car = new Audi();
break;
case "BMW":
car = new BMW();
break;
}
return car;
}
}
然后在控制台的代码可以改成以下代码:
Car car1 = new CarFactory().CreateCarType("Audi"); //通过简单工厂类获取奥迪对象
Car car2 = new CarFactory().CreateCarType("BMW"); //通过简单工厂类获取宝马对象
car1.CreateCar();
car2.CreateCar();
Console.Read();
UML图如下:
最终输出结果是一样的,如果需要把宝马改成奥迪,那简单,修改CarFactory类中的代码即可,这样一来,是不是轻松多了。或者把工厂类中carType变量抽到配置文档中,由配置文档配置,就可以实现不修改代码的请况下随意配置奥迪或者宝马。
public class CarFactory
{
private Car car = null;
//可以从配置文档配置:carType,更换实例对象
private static readonly string carType = ConfigurationManager.AppSettings["carType"];
public Car CreateCarType()
{
switch (carType)
{
case "Audi":
car = new Audi();
break;
case "BMW":
car = new BMW();
break;
}
return car;
}
}
但是,这样设计虽然降低了对象之间的耦合,却违背了软件设计的开闭原则:比如说,现在要添加一个奔驰的实现类,那么就必须在工厂类中添加一个case 条件来生成奔驰的实例,要怎么搞??
二. 工厂方法
屏蔽对象创建,留下扩展空间,完美遵循开闭原则。
为了解决简单工厂模式系统难以扩展,一旦添加新产品就不得不修改简单工厂方法的缺点,出现了工厂方法模式。
/// <summary>
/// 抽象工厂类
/// </summary>
public abstract class AbstractFactory
{
public abstract Car CreateCarType();
}
/// <summary>
/// 奥迪工厂类
/// </summary>
public class AudiFactory : AbstractFactory
{
public override Car CreateCarType()
{
return new Audi();
}
}
/// <summary>
/// 宝马工厂类
/// </summary>
public class BMWFactory : AbstractFactory
{
public override Car CreateCarType()
{
return new BMW();
}
}
控制台代码:
AbstractFactory audiFactory = new AudiFactory();
AbstractFactory bmwFactory = new BMWFactory();
Car car1 = audiFactory.CreateCarType(); //通过工厂方法获取奥迪对象
Car car2 = bmwFactory.CreateCarType(); //通过工厂方法获取宝马对象
car1.CreateCar();
car2.CreateCar();
Console.Read();
使用工厂方法实现的系统,如果系统需要添加新产品时,我们可以利用多态性来完成系统的扩展,对于抽象工厂类和具体工厂中的代码都不需要做任何改动。
例如:如果要添加一个奔驰类,那么只需要再写一个奔驰工厂类,实现抽象工厂的方法即可返回奔驰类的对象实例,控制台就可以调用奔驰工厂类的方法获取对象实例了。
UML图:
三. 抽象工厂
屏蔽对象创建,约束强制保障产品簇
但是在现实生活中,一个工厂只创建单个产品这样的例子很少,因为现在的工厂都多元化了,一个工厂创建一系列的产品,如果我们要设计这样的系统时,工厂方法模式显然在这里不适用,然后抽象工厂模式却可以很好地解决一系列产品创建的问题,
例如,在上面的例子中,我们要求形成一个交通工具产品簇的企业工厂,包括汽车、自行车、摩托车。缺一不可,怎么做呢?
首先,我们先把其他交通工具的类写了,
/// <summary>
/// 自行车抽象类
/// </summary>
public abstract class Bicycle
{
public abstract void CreateBicycle();
}
/// <summary>
///奥迪
/// </summary>
public class AudiBicycle : Bicycle
{
public override void CreateBicycle()
{
Console.WriteLine("制造奥迪自行车");
}
}
/// <summary>
/// 宝马
/// </summary>
public class BMWBicycle : Bicycle
{
public override void CreateBicycle()
{
Console.WriteLine("制造宝马自行车");
}
}
/// <summary>
/// 摩托车抽象类
/// </summary>
public abstract class Motorbike
{
public abstract void CreateMotorbike();
}
/// <summary>
/// 奥迪
/// </summary>
public class AudiMotorbike : Motorbike
{
public override void CreateMotorbike()
{
Console.WriteLine("制造奥迪摩托车");
}
}
/// <summary>
/// 宝马
/// </summary>
public class BMWMotorbike : Motorbike
{
public override void CreateMotorbike()
{
Console.WriteLine("制造宝马摩托车");
}
}
然后,开始创建抽象工厂,强制约束,保障产品簇
/// <summary>
/// 抽象工厂:要求必须有汽车、自行车、摩托车,形成交通工具产品簇
/// </summary>
public abstract class AbstractFactory
{
public abstract Car CreateCarType();
public abstract Bicycle CreateBicycleType();
public abstract Motorbike CreateMotorbikeType();
}
那么,宝马工厂和奥迪工厂继承了以上的抽象工厂,就必须生产要汽车、摩托车、自行车的完整产品簇
/// <summary>
/// 奥迪交通工具产品簇
/// </summary>
public class AudiFactory : AbstractFactory
{
public override Bicycle CreateBicycleType()
{
return new AudiBicycle();
}
public override Car CreateCarType()
{
return new Audi();
}
public override Motorbike CreateMotorbikeType()
{
return new AudiMotorbike();
}
}
/// <summary>
/// 宝马交通工具产品簇
/// </summary>
public class BMWFactory : AbstractFactory
{
public override Bicycle CreateBicycleType()
{
return new BMWBicycle();
}
public override Car CreateCarType()
{
return new BMW();
}
public override Motorbike CreateMotorbikeType()
{
return new BMWMotorbike();
}
}
这样一来,就能够通过AudiFactory 或者BMWFactory 获取他们的 汽车、自行车、摩托车的对象实例。
UML图如下:
四. 三种工厂模式的使用选择
简单工厂 : 用来生产同一等级结构中的任意产品。(不支持拓展增加产品)
工厂方法 : 用来生产同一等级结构中的固定产品。(支持拓展增加产品)
抽象工厂 : 用来生产不同产品族的全部产品。(支持拓展增加产品;支持增加产品族)
写到这里,一定有小伙子开始郁闷了!这不是脱裤子放屁?感觉有时候还不如直接new一个对象,怎么说呢?如果项目做大,如果创建对象的时候需要做一些处理,那就可以考虑使用工厂模式了。 使用工厂可以增加一些逻辑(例如IOC)屏蔽对象实例化的复杂度。
还是那句话:没有最好的设计模式,只有最合适的设计模式!