工厂模式在当初学习.net时就听说过,记得当初实习的简历上写着熟悉三层架构和工厂模式,其实当初并不会,只是听说过。直到前些时候才去了解工厂模式,其实工厂模式还是很常用的,参考大话设计模式和网上的若干博客,初步整理出四种版本的,简单工厂模式、工厂模式、改进的反射工厂模式、抽象工厂模式。
首先先大概了解下实际运用背景,比如要设计一个集成平台将停车场集成进来,而停车场有多个品牌供用户选择,这种情况就需要运用工厂模式。将停车场的特征方法提取出来,每新加一种停车场时实现该方法即可,客户端只需少许更改即可实现动态选择产品。
首先不使用工厂模式实现:
public class ParkA
{
public void GetParkInfo()
{
Console.WriteLine("ParkA");
}
}
public class ParkB
{
public void GetParkInfo()
{
Console.WriteLine("ParkB");
}
}
客户端:
class Program
{
static void Main(string[] args)
{
ParkA park = new ParkA();
park.GetParkInfo();
Console.ReadLine();
}
}
这客户端是用ParkA,又一客户用ParkB,把这段代码去掉换成ParkB交给客户,第三个客户用ParkA,只能再改回ParkA,第一个客户和第三个客户明明一样,但也没法直接用(因为第二个客户时已经改成ParkB了),如此很多时侯就是在做重复劳动,而且每卖一个都要开发人员根据其品牌修改一番。
1.简单工厂
简单工厂上场,面向接口编程,将选择品牌的过程交给客户,将停车场提取出接口,每个品牌都实现这个接口,然后提供一个工厂,用户只要选择自己的品牌即可。
public interface IPark
{
void GetParkInfo();
}
public class ParkA : IPark
{
public void GetParkInfo()
{
Console.WriteLine("ParkA");
}
}
public class ParkB : IPark
{
public void GetParkInfo()
{
Console.WriteLine("ParkB");
}
}
public enum ParkTypeEnum
{
ParkA,
ParkB
}
public class ParkFactory
{
public static IPark CreatePark(ParkTypeEnum parkType)
{
switch (parkType)
{
case ParkTypeEnum.ParkA:
return new ParkA();
case ParkTypeEnum.ParkB:
return new ParkB();
default:
return null;
}
}
}
客户端:
class Program
{
static void Main(string[] args)
{
IPark park = ParkFactorys.ParkFactory.CreatePark(ParkTypeEnum.ParkA);
park.GetParkInfo();
Console.ReadLine();
}
}
当有新品牌时只需实现接口,修改工厂即可。而对于已有的品牌则无需修改。
这里有个理论依据,里氏替换法则:任何接收父类型的地方,都应当能够接收子类型,换句话说如果使用的是一个基类的话,那么一定适用于其子类,而且程序察觉不出基类对象和子类对象的区别。
开放封闭原则:对扩展是开放的,而对修改是封闭的。
缺点:违反了开放封闭原则,对修改开放了,在增加一个新的品牌时必须相应增加工厂的switch分支。
2.工厂模式
相对简单工厂变化之处,就是工厂发生了变化,将工厂也抽象出来一个工厂接口,里面只有一个方法,用来创建实例。每个品牌都有自己的工厂,各自实现工厂接口即可。
public interface IPark
{
void GetParkInfo();
}
public class ParkA : IPark
{
public void GetParkInfo()
{
Console.WriteLine("ParkA");
}
}
public class ParkB : IPark
{
public void GetParkInfo()
{
Console.WriteLine("ParkB");
}
}
public interface IFactoryPark
{
IPark CreatePark();
}
public class ParkFactoryA : IFactoryPark
{
public IPark CreatePark()
{
return new ParkA();
}
}
public class ParkFactoryB : IFactoryPark
{
public IPark CreatePark()
{
return new ParkB();
}
}
客户端:
class Program
{
static void Main(string[] args)
{
IFactoryPark factory = new ParkFactoryA();
IPark park=factory.CreatePark();
park.GetParkInfo();
Console.ReadLine();
}
}
这样就符合了开放封闭原则,新加品牌同时新加相应的工厂,而无需修改原有的工厂。
缺点:品牌多了之后工厂也会随之变得很多。
3.反射工厂模式
针对简单工厂模式,还有一种改进,利用反射来封闭修改。修改工厂类,如下:
public class ParkFactory
{
public static IPark CreatePark(string typeName)
{
#region 方法一
//load中是程序集的名称,也就是生成的DLL的名称
//CreateInstance后面的是类的完整名称,带命名空间
//IPark park = Assembly.Load("ParkFactorys").CreateInstance(typeName) as IPark;
#endregion
#region 方法二
//GetType的参数需是类的完整名称,带命名空间
Type type = Type.GetType(typeName, true);
IPark park = Activator.CreateInstance(type) as IPark;
#endregion
return park;
}
}
客户端:
class Program
{
static void Main(string[] args)
{
IPark park = ParkFactory.CreatePark("ParkFactorys.ParkA");
park.GetParkInfo();
Console.ReadLine();
}
}
4.抽象工厂模式
以上的三种的产品扩展都是针对同一个系列,当有多个时需要工厂里将每个系列一个个的抽象,这时就要抽象工厂模式。
比如如下例子,除了集成停车场,现在也要集成汽车,这时就需要在工厂接口里增加创建汽车接口的方法,抽象工厂是对工厂模式的继续扩充。
public interface IPark
{
void GetParkInfo();
}
public class ParkA : IPark
{
public void GetParkInfo()
{
Console.WriteLine("ParkA");
}
}
public class ParkB : IPark
{
public void GetParkInfo()
{
Console.WriteLine("ParkB");
}
}
public interface ICar
{
void Run();
}
public class CarA : ICar
{
public void Run()
{
Console.WriteLine("CarA Run");
}
}
public class CarB : ICar
{
public void Run()
{
Console.WriteLine("CarB Run");
}
}
public interface IFactory
{
IPark CreatePark();
ICar CreateCar();
}
public class ParkFactoryA : IFactory
{
public IPark CreatePark()
{
return new ParkA();
}
public ICar CreateCar()
{
return new CarA();
}
}
public class ParkFactoryB : IFactory
{
public IPark CreatePark()
{
return new ParkB();
}
public ICar CreateCar()
{
return new CarB();
}
}
客户端:
class Program
{
static void Main(string[] args)
{
IFactory factory = new ParkFactoryA();
IPark park=factory.CreatePark();
park.GetParkInfo();
ICar car = factory.CreateCar();
car.Run();
Console.ReadLine();
}
}
最后简单的总结:
简单工厂:简单实用,但违反开放封闭;
工厂方法:开放封闭,单一产品;
抽象工厂:开放封闭,多个产品;
反射工厂:可以最大限度的解耦。
源码下载