工厂模式
我们在编程的时候,每当"new"一个对象之后,这个对象就依赖于这个类了。如果在后期的维护过程中由于某些原因需要修改一下这个类,则唯一的做法就是打开源代码,进行修改,修改所有与这个对象有关的操作。这对我们是非常不利的。
问题出来了:对象不能应对“具体实例化类型”的变化
解决思路:封装变化点,哪里变化,封装哪里。在这个例子中,要实例化的类变了,就将实例化这个操作封装起来,我们可以把"new"这个操作移交一个具体的类,由它去负责根据我们的条件创建具体类的实例,也就是下面要说的“简单工厂模式”。
现实生活中例子:
每次参加不同的聚会或者与不同的人见面,可能穿的衣服是不一样的,比如,你今天上午要与你的一个新客户见面,你可能会对你的老婆说:老婆,给拿件商务装(参数),我要去见我的一个客户,你老婆(工厂类)接到你的请求(商务装参数)后,从衣柜中取出一件商务装(具体产品),交给你。整个过程就完成了。
分析:
你可能根据不同的条件,要的衣服是不一样的,但要的衣服都是已经在你的衣柜中存在的。并且,每件上衣它们都属于同一种抽象,即它们可以从一个抽象类或接口中继承,这此衣服各自都有一定特征,这些都是条件。然后你要的时候,就可以向你老婆说一种特征,她就会根据这个特征为你服务了。这就是典型的简单工厂模式的应用。
抽象产品类代码
/// <summary>
/// 抽象产品类:上衣
/// </summary>
public interface ICoat
{
void GetYourCoat();
}
具体产品类代码
namespace SimpleFactory
{
<summary>
/// 具体产品类:商务上衣
/// </summary>
public class BusinessCoat:ICoat
{
public void GetYourCoat()
{
Console.WriteLine("商务上衣");
}
}
<summary>
/// 具体产品类:时尚上衣
/// </summary>
public class FashionCoat : ICoat
{
/** <summary>
/// 实现ICoat中定义的方法
/// </summary>
/// <returns></returns>
public void GetYourCoat()
{
Console.WriteLine("时尚上衣");
}
}
}
简单工厂模式中最核心的部分:工厂类
namespace SimpleFactory
{
<summary>
/// 简单工厂模式中的核心部分:工厂类
/// </summary>
public class Factory
{
public ICoat CreateCoat(string styleName)
{
switch (styleName.Trim().ToLower())
{
case "business":
return new BusinessCoat();
case "fashion":
return new FashionCoat();
default :
throw new Exception("还没有你要的那种衣服");
}
}
}
}
再看一下客户在调用的时候的代码
<summary>
/// 客户类
/// </summary>
class Client
{
static void Main(string[] args)
{
ICoat food;
try
{
Factory factory = new Factory();
Console.Write("我要的是时尚上衣\t");
food = factory.CreateCoat("fashion");
food.GetYourCoat();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
在客户端的代码中有我们就可以根据具体的参数,返回我们希望返回的对象,将"new"操作推迟到工厂类中实现。
这里,参数我直接写上了,我们其实可以将这个参数写到一个xml文件中,如app.config文件中,动态的读出来,需要穿另外一种衣服了,只需要打开app.config文件,修改里面的值就行了,不需要项目重新编译。这样这个小程序就能够适应一定的变化了,其实它也是设计模式正要解决的问题,在不修改代码的情况下,使项目能够适应一定的客户需求变化。
但这样又有一个新的问题,当添加一个新的衣服种类的时候,我们不但要添加一个新的衣服类,而且还要修改工厂类,为了解决这个问题,可以采用反射,需要修改一下工厂类
namespace SimpleFactory
{
<summary>
/// 简单工厂模式中的核心部分:工厂类
/// </summary>
public class Factory
{
public ICoat CreateCoat(string className)
{
string assemblyName = "程序集名";
ICoat instance;
if(factoryName != "")
{
instance = (ICoat)Assembly.Load(assemblyName).CreateInstance(className);
}
else
{
instance = null;
}
}
}
}
这样,需要添加一个新的种类得时候,就不需要修现有代码了