重构:将单例模式从业务类中完全解耦
先来看看Singleton的用例图:
在一个实际的老项目中,有很多的业务类,也不知道当时如何设计的,这些业务类均被设计成了Singleton模式。
项目中这些业务类结构如下:
而每个业务类的设计均为单例,诸如:
public class SearchHelper { private object obj = new object(); private static SearchHelper search; private SearchHelper(){} public static SearchHelper Instance { get { if (search == null) { lock (obj) { if (search == null) search = new SearchHelper(); } } return search; } } public string GetSearch() { return "Path"; } }
这种设计初初一看,就不是很顺眼。
这种业务类和单例本身强结合的模式,实际应用中,还真带来了一些麻烦,比如这个SearchHelper, 我有时候需要对某些方法获取更新某实体后的值,因其单例类模式,直接就无法得到其值,只好绕弯路。
于是重构这个模块,已经是摆在面前。 当然也可以不去重构,让代码继续乱下去,乱下去,乱下去,直到死亡 :-)
经过一番考虑,首先想到的是将这些业务类和单例这个模式强结合的模式分离, 分离后让单例不再强奸这些业务类。
于是,就有了下文:
第一步:将这些业务类的单例去除,出除后,代码结构如下:
public class SearchHelper { private SearchHelper(){} public string GetPath() { return "Path"; } }
同理,去除其他所有的业务类的单例。
PathHelper:
public class PathHelper { private PathHelper(){} public string GetPath() { return "Path"; }
}
MapHelper:
public class MapHelper {
private MapHelper(){} public string GetMap() { return "Map"; } }
第二步:定义个单例专用类,定义一个泛型类,并利用反射特性使其能够动态按需创建单例
public class Singleton<T> where T : class { static Mutex mutex = new Mutex(); static T instance; private Singleton() { } public static T UniqueInstance { get { mutex.WaitOne(); // enter protected area if (instance == null) { try { instance = SingletonCreator.instance; } catch (Exception ex) { throw ex; } } mutex.ReleaseMutex(); // exit protected area return instance; } } class SingletonCreator { static SingletonCreator() { } // Private object instantiated with private constructor internal static readonly T instance = CreateNewInstance(); private static T CreateNewInstance() { //Get the current assembly object Assembly assembly = Assembly.GetExecutingAssembly(); // Retrieve assembly types Type[] types = assembly.GetTypes(); foreach (Type typeName in types) { Module typeMod = assembly.GetModule(typeName.ToString()); if (typeof(T).IsAssignableFrom(typeName) && (typeName.IsClass)) { // Create and return an instance of the appropriate model object return Activator.CreateInstance(typeName) as T; } } throw new Exception("New instance not found!"); } } }
第三步: 定义一个Dispatcher类,用以得到泛型类的单例。
1 public class Dispatcher 2 { 3 public static T BuildObject<T>() where T : class 4 { 5 return Singleton<T>.UniqueInstance; 6 } 7 }
第四步: 定义一个Facades类,用以得到想要的具体的某业务类的单例。
1 public class Facades 2 { 3 private static SearchHelper searchHelper; 4 private static MapHelper mapHelper; 5 private static PathHelper pathHelper; 6 7 public SearchHelper SearchHelper 8 { 9 get { return searchHelper; } 10 } 11 12 public MapHelper MapHelper 13 { 14 get { return mapHelper; } 15 } 16 17 public PathHelper PathHelper 18 { 19 get { return pathHelper; } 20 } 21 public Facades() 22 { 23 searchHelper = Dispatcher.BuildObject<SearchHelper>(); 24 mapHelper = Dispatcher.BuildObject<MapHelper>(); 25 pathHelper = Dispatcher.BuildObject<PathHelper>(); 26 } 27 }
好了,到此为止,已经将单例模式从业务类中完全解耦。
业务类就是业务来,单例就是单例,无需将单例强加在业务类上。重构后,其文件结构如下: