一、背景
最近在工作中,要修改离职的同事的代码,发现有一个函数代码长度达到了1000行,让我痛不欲生。看过之后发现里面大部分是if...else构成的代码,这应该就是迭代频繁的产物吧。于是为了看着舒服,就着手改造了一下。
二、什么时候采用工厂模式
使用工厂模式当然不仅仅是为了代码看着舒服(我个人是喜欢代码看起来比较舒服),也不是为了使代码看起来更牛叉(我个人是喜欢代码看起来比较牛叉),而是为了是代码的可拓展性更高,可阅读性更高,修改起来比较方便。
当根据需求要产生不同的东西的时候,并且需求种类很多的情况下。
三、举个例子
假设有一个买家,他想买衣服、想买裤子、想买鞋子。他就要亲自去干很多事情。
假设有很多不赚差价的中间商,他们可以帮你买衣服,帮你买裤子,帮你买鞋子。那么现在这个买家,他不用自己去找衣服厂家买衣服,他可以找这个不赚差价的中间商,中间商会帮他处理一切细节,最终给他一件衣服。
首先我们先把这些中间商给实现了
1 /// <summary> 2 /// 中间商接口 3 /// </summary> 4 public interface IMiddleman 5 { 6 string Shopping(); 7 } 8 9 /// <summary> 10 /// 中间商接口基类 11 /// </summary> 12 public abstract class BaseMiddleman : IMiddleman 13 { 14 public abstract string Shopping(); 15 } 16 17 /// <summary> 18 /// 衣服中间商 19 /// </summary> 20 public class ClothesMiddleman : BaseMiddleman 21 { 22 public override string Shopping() 23 { 24 return "给你买来了衣服"; 25 } 26 } 27 28 /// <summary> 29 /// 裤子中间商 30 /// </summary> 31 public class TrousersMiddleman : BaseMiddleman 32 { 33 public override string Shopping() 34 { 35 return "给你买来了裤子"; 36 } 37 } 38 39 /// <summary> 40 /// 鞋子中间商 41 /// </summary> 42 public class ShoesMiddleman : BaseMiddleman 43 { 44 public override string Shopping() 45 { 46 return "给你买来了鞋子"; 47 } 48 }
为什么这里要定义接口,因为可能有不同的中间商嘛。那为什么有基类,因为有部分中间商干的事情是一样的嘛。
其实中间商不一定只给你买衣服,他还可能给你全套服务,比如售前、售后、询底价、试穿。。。那只需要拓展一下接口,基类实现一下,个别实现不同的话重写一下,就OK了。
那么现在要买衣服只需要
1 static void Main(string[] args) 2 { 3 var cloths = new FactoryDemo.ClothesMiddleman().Shopping(); 4 var trousers = new FactoryDemo.TrousersMiddleman().Shopping(); 5 var shoes = new FactoryDemo.ShoesMiddleman().Shopping(); 6 Console.WriteLine(cloths); 7 Console.WriteLine(trousers); 8 Console.WriteLine(shoes); 9 10 Console.ReadKey(); 11 }
那么问题来了,虽然这个买家不用自己亲自去买衣服了,但他还是要找不同的中间商买,那就很麻烦。(好懒啊!)
现在有这么个中间商管理员,你只需要告诉这个中间商管理员,你想要什么,他会去给你找不同的中间商,最终给你想要的。
1 /// <summary> 2 /// 中间商管理员 3 /// </summary> 4 public static class MiddlemanManager 5 { 6 /// <summary> 7 /// 购物类别枚举 8 /// </summary> 9 public enum EShoppingType 10 { 11 衣服, 12 裤子, 13 鞋子 14 } 15 16 static Dictionary<EShoppingType, IMiddleman> _ManagerDic; 17 18 /// <summary> 19 /// 中间商管理员库 20 /// </summary> 21 static Dictionary<EShoppingType, IMiddleman> ManagerDic 22 { 23 get 24 { 25 if (_ManagerDic == null) 26 { 27 lock (typeof(MiddlemanManager)) 28 { 29 if (_ManagerDic == null) 30 { 31 _ManagerDic = new Dictionary<EShoppingType, IMiddleman>() 32 { 33 { EShoppingType.衣服, new ClothesMiddleman() }, 34 { EShoppingType.裤子, new TrousersMiddleman() }, 35 { EShoppingType.鞋子, new ShoesMiddleman() } 36 }; 37 } 38 } 39 } 40 return _ManagerDic; 41 } 42 } 43 44 /// <summary> 45 /// 获取实例化的中间商 46 /// </summary> 47 public static IMiddleman Create(EShoppingType type) 48 { 49 return ManagerDic[type]; 50 } 51 }
好了,这下管理员也有了,买家只需要找管理员要东西就行了。这里管理员的库用的是硬编码的字典,其实还有很多方式,比如常用的反射。我更喜欢硬编码的字典、XML配置文件、数据库等。
1 static void Main(string[] args) 2 { 3 var cloths = FactoryDemo.MiddlemanManager.Create(FactoryDemo.MiddlemanManager.EShoppingType.衣服).Shopping(); 4 var trousers = FactoryDemo.MiddlemanManager.Create(FactoryDemo.MiddlemanManager.EShoppingType.裤子).Shopping(); 5 var shoes = FactoryDemo.MiddlemanManager.Create(FactoryDemo.MiddlemanManager.EShoppingType.鞋子).Shopping(); 6 Console.WriteLine(cloths); 7 Console.WriteLine(trousers); 8 Console.WriteLine(shoes); 9 10 Console.ReadKey(); 11 }
好了,这样只需要找管理员,告诉这个管理员我需要什么,其他的都不用买家去做,一条龙服务。
四、结语
第一次写博客,写了这么多,发现写写文章还是蛮累的,把想法表达出来还真的蛮难的。