接上文,项目交付之后,我们的类库开发人员发现自己穿越了,回到【设计模式——2、简单工厂模式】这篇文章所在时间线的最末尾。
由于穿越所造成的蝴蝶效应,这个项目后期虽然确实需要扩展,但是只是要增加五到六个产品类,并要求尽快交付,以便将关注点放到其他更有价值的项目中去,那赶快来扩充我们的简单工厂吧。
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;
case "HISTORY":return new HistoryDal();break;
...
}
}
}
代码很快写完了,测试通过,但是下一步sonar代码质量检测,在工厂类的CreateProduct方法里却发现两个问题,
第一是return和break那里有坏味道,也是,都已经return了,还怎么break?(好吧,是我强行这么写只是为了推荐一下sonar),那就改成switch里用变量赋值,最后再return那个变量吧。
第二是方法圈复杂度刚好超过10了,这个扎心了,没法解决,重构吧!
基本思路:用字典代替switch分支
//工厂类
public class Factory
{
public static readonly Dictionary<string, IProduct> dictionary = new Dictionary<string, IProduct>()
{
{ "USER", new UserDal() },
{ "GOODS", new GoodsDal() },
{ "HISTORY", new HistoryDal() },
...
};
/// <summary>
/// 静态方法创建Product实例
/// </summary>
public static IProduct CreateProduct(string name)
{
return dictionary[name];
}
}
现在圈复杂度的问题彻底解决了,我们通过静态常量dictionary和静态方法CreateProduct实现的,唯一的缺点是在第一次调用Factory的时候,会把所有对象创建一次,要知道这可是单层架构,所有的初始化工作都在里面了,性能何在?加入Lazy<T>延迟加载后能很好地解决这个问题!
//工厂类
public class Factory
{
public static readonly Dictionary<string, Lazy<IProduct>> dictionary = new Dictionary<string, Lazy<IProduct>>()
{
{ "USER", new Lazy<IProduct>(() => new UserDal(), true) },
{ "GOODS", new Lazy<IProduct>(() => new GoodsDal(), true) },
{ "HISTORY", new Lazy<IProduct>(() => new HistoryDal(), true) },
...
};
/// <summary>
/// 静态方法创建Product实例
/// </summary>
public static IProduct CreateProduct(string name)
{
return dictionary[name].Value;
}
}
现在产品对象只会在第一次调用的时候创建,而不是调用Factory的时候全部创建。
继续来看,项目组觉得这个方案很有价值,要求以后用到简单工厂的项目都这样干。做法就是所有的简单工厂类必须去实现ISampleFactory这个接口。
public interface ISampleFactory
{
Dictionary<string, Lazy<IProduct>> Products { get; set; }
IProduct CreateProduct(string name);
}
前面通过静态常量和静态方法做的工作,随着接口的出现,全部作废了。因为静态和接口是宿敌了,一个是面向过程的方法集合,一个是面向对象的高阶面向接口。接口里定义的属性和方法只有对象才能调用,而静态类压根就没有对象。
实现接口的类不能是静态的,类所实现的属性和方法也不能是静态的,所以静态用不了,而且Products也从常量变成了属性。
静态被否定了,也只能用单例模式了。我们可以把Dictionary<string, Lazy<IProduct>> Products这个字段的初始化放到私有构造函数里,而单例模式只有一个实例,不就意味着Products只会被初始化1次喽。
//工厂类
public class Factory : ISampleFactory
{
private static Factory instance;//静态实例
private Factory()
{
Products = new Dictionary<string, Lazy<IProduct>>
{
{ "USER", new Lazy<IProduct>(() => new UserDal(), true) },
{ "GOODS", new Lazy<IProduct>(() => new GoodsDal(), true) },
{ "HISTORY", new Lazy<IProduct>(() => new HistoryDal(), true) },
...
};
}
public static Factory GetInstance()//方法,方法中去实例化类.
{
if (instance == null)
{
instance = new Factory();
}
return instance;
}
public Dictionary<string, Lazy<IProduct>> Products { get; set; }
IProduct ISampleFactory.CreateProduct(string name)
{
return Products[name].Value;
}
}
好了,运用单例模式完美的解决了接口与静态的矛盾,单例模式真的是非常给力的设计模式。
待续。。。