那个建造工厂的人建造了一座庙宇…
工厂模式的作用
Factory模式允许我们只依赖于抽象接口就能创建出具体对象的实例。所以,如果具体类是高度易变的,那么该模式非常有用。
代码与案例
以代工厂生产手机为例。
1.创建手机的抽象父类与各种手机品牌的实体类
代工厂生产手机为例:Xiaomi,Oppo,Vivo…Phone
//创建Phone父类
public abstract class Phone
{
//所有的手机都能打电话
public abstract void Call();
}
//各种手机品牌
public class Xiaomi : Phone
{
public override void Call()
{
Console.WriteLine("Xiaomi Calling");
}
}
public class Oppo : Phone
{
public override void Call()
{
Console.WriteLine("Oppo Calling");
}
}
public class Vivo : Phone
{
public override void Call()
{
Console.WriteLine("Vivo Calling");
}
}
2.创建工厂及具体工厂
//创建工厂:IPhoneFactory
public interface IPhoneFactory
{
public Phone CreatePhone();
}
具体工厂:用来创建实体类的实例对象。也可以理解为代工的各类手机品牌的具体生产线。继承IPhoneFactory
//Xiaomi生产线
public class XiaomiFactory : IPhoneFactory
{
public Phone CreatePhone()
{
return new Xiaomi();
}
}
//Oppo生产线
public class OppoFactory : IPhoneFactory
{
public Phone CreatePhone()
{
return new Oppo();
}
}
//Vivo生产线
public class VivoFactory : IPhoneFactory
{
public Phone CreatePhone()
{
return new Vivo();
}
}
3.使用工厂类创建实体类的实例对象
class Program
{
static void Main(string[] args)
{
//使用:可以想象为客户下订单生产Oppo型号手机
//开启OPPO的生产线
IPhoneFactory factory = new OppoFactory();
Phone phone=factory.CreatePhone();
phone.Call();
Console.ReadLine();
}
}
结构解析
客户端要生产一个具体产品时,首先要获取这个产品对应的具体工厂实例,然后通过具体工厂来实例化产品。所以,如果要新增品牌的时候,只需要增加一个实体类及实体类的具体工厂类即可。
public abstract class Phone{} //抽象的父类:以实现多态。
public interface IPhoneFactory{public Phone CreatePhone();} //抽象工厂:创建具体工厂实例
public class Oppo : Phone{} //实体类、实现类,继承父类
public class OppoFactory : IPhoneFactory //具体工厂类:实例化具体产品
{
public Phone CreatePhone(){ return new Oppo();}
}
优缺点
优点:
- 工厂模式有效地解决了添加新实体时必须要修改工厂类代码的问题,符合设计原则中的
开闭原则
- 客户端无需负责对象的创建,更好的明确了各个类的职责
- 如果有新的对象增加,只需要增加一个具体的实体类和具体的工厂类即可
- 不会影响已有的代码,后期维护容易,增强系统的扩展性
- 典型的解耦框架。高层模块(客户端)只需要知道产品的抽象类,其他的实现类都不需要关心,符合
迪米特法则
,符合依赖倒置原则
,符合里氏替换原则
。
缺点: 需要额外的代码编写,增加了工作量。如果实体少,且比较固定的话,用简单工厂模式
也可以。
工厂模式配合反射使用
using System.IO;
using System.Configuration;
using System.Reflection;
using CNBlogs.DesignPattern.Common;
class Program
{
static void Main(string[] args)
{
// 工厂类的类名写在配置文件中可以方便以后修改
string factoryType = ConfigurationManager.AppSettings["Oppo"];
// 这里把DLL配置在数据库是因为以后数据可能发生改变
// 比如说现在的数据是从sql server取的,以后需要从oracle取的话只需要添加一个访问oracle数据库的工程就行了
string dllName = ConfigurationManager.AppSettings["DllName"];
// 利用.NET提供的反射可以根据类名来创建它的实例,非常方便
var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
string codeBase = currentAssembly.CodeBase.ToLower().Replace(currentAssembly.ManifestModule.Name.ToLower(), string.Empty);
IPhoneFactory factory = Assembly.LoadFrom(Path.Combine(codeBase, dllName)).CreateInstance(factoryType) as IPhoneFactory;
Phone phone = factory.CreatePhone();
phone.Call();
}
}