设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。对这句话最好解读就是简单工厂,因为他不属于经典设计模式的范畴,但确实是用到特别多的模式。
使用场景
1)工厂类负责创建的对象比较少;
2)客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心;
public class Factory{
public static ISample creator(int which){
if (which==1)
return new SampleA();
else if (which==2)
return new SampleB();
}
}
针对条件1,代码审读要求方法的圈复杂度不能大于10,这里的which已经很有限了。
当然,您尽可以使用诸如泛型甚至委托来取代if判断,使其不存在圈复杂度的问题。但人家这里说的问题应该是指可扩展性,可维护性的问题吧。
看百度百科上说的:
缺点:
由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。
当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;
eg
真正的应用场景与分析:
小型网站项目,没有复杂的业务逻辑,只有最基本的增删改查,采用单层架构,一个数据访问的类库+网站,类库包括UserDal,GoodsDal,HistoryDal三个模块,两名开发人员,一个负责类库,一个负责网站【这里更多的工作是UI了】,这时候,为了明确了各自的职责和权利,使网站开发员尽量少的关心类库的开发细节,需要类库那边提供工厂类来创建对象。使网站开发员只需要知道参数,就能消费对象。
//产品基类
public class BaseEntity
{
public string Id{get;set;}
}
//产品接口
public interface IProduct
{
bool Add(BaseEntity entity);
bool Del(string id);
bool Edit(string id);
bool Select(string id);
}
//工厂类
public class Factory
{
/// <summary>
/// 静态方法创建Product实例
/// </summary>
public static IProduct CreateProduct(string name)
{
switch(name)
{
case "USER":return new UserDal();break;
case "GOODS":return new GoodsDal();break;
...
}
}
}
可以发现,简单工厂需要所有的产品类都实现IProduct接口,才能创建对象。IProduct内部定义了增删改查的方法,所有的产品类都去实现这四个方法,这就是简单工厂的应用了。
现在呢,开发人员有一个问题,他说我的HistoryDal(日志)这个模块只需要添加和查询,并不需要删改,怎么办呢?
怎么办?留空吗,因为接口必须全部实现,不写会报错的,所以最后上线的时候,HistoryDal里的代码就是这样的:
public class HistoryDal : IProduct
{
bool IProduct.Add(BaseEntity entity)
{
return new Repository().Add(entity);
}
bool IProduct.Del(string id)
{
throw new NotImplementedException();
}
bool IProduct.Edit(string id)
{
throw new NotImplementedException();
}
bool IProduct.Select(string id)
{
return new Repository().FindByID<History>(id);
}
}
好了,第一个并不算问题的问题解决了,开发人员又说了,他还有一个问题。三个模块里面,有的模块需要返回多条数据,还有的模块的查询是需要做分页的,这怎么办呢?
那就在接口里把这两个方法都添加进去吧,最后的接口是这样的,不需要实现的就留空吧,跟上面一样。
//产品接口
public interface IProduct
{
bool Add(BaseEntity entity);
bool Del(string id);
bool Edit(string id);
bool Select(string id);
IList<BaseEntity> GetEntitys();
IList<BaseEntity> GetEntitys(int pageIndex,int pageSize,out int totalCount);
}
这时候,开发人员又说了,如果后续咱的项目火了,会增加很多产品类,成千上万那么多,那么
第一,你的工厂类要炸了,请问,我到底要写多少判断语句才能搞定?圈复杂度十几万了吧!当然,这个工厂类我大可以不用判断语句,可以用泛型for循环,委托,观察者模式,等等等等,使代码能看,好吧,这姑且算是个程序问题
第二,你这个IProduct这个接口是真的炸了,我到底要在里面定义多少方法,才能顾及到所有的产品?而且我的产品类里岂不全是空方法吗?真正的实现找起来都费劲。这个可就100%的设计问题了。
好吧,咱现在不就三个产品类么?先这么用着吧。等后面产品类多了,咱可以顺势改用工厂模式吗!
下篇 设计模式——3、工厂模式