工厂模式
工厂模式理论我不长篇大论了。其核心功能是根据“需求”生产“产品”,设计模式的核心是解耦。工厂模式就是为了解耦“需求”和“产品”,但是别忘了,工厂模式工厂模式,还有一个重要元素,就是“工厂”,所以工厂模式的核心思想,就是解耦“需求”“工厂”和“产品”。
工厂模式,实际上也会根据业务情景不同会有不同的实现方式。一般分为3种。简单工厂,工厂和抽象工厂。
关键点:
一、三种工厂的实现是越来越复杂的
二、简单工厂通过构造时传入的标识来生产产品,不同产品都在同一个工厂中生产,这种判断会随着产品的增加而增加,给扩展和维护带来麻烦
三、工厂模式无法解决产品族和产品等级结构的问题
四、抽象工厂模式中,一个工厂生产多个产品,它们是一个产品族,不同的产品族的产品派生于不同的抽象产品(或产品接口)。
五、用哪种工厂模式,取决于业务需求,不要认为简单工厂是用switch case就觉得一无是处,也不要觉得抽象工厂比较高大上就到处套。要根据三种工厂模式的特质,来确定使用哪种解决问题。
简单工厂
1 int prodNo; 2 public SimpleFactory(int prodNo) //构造工厂时告知工厂产品标识 3 { 4 this.prodNo = prodNo; 5 } 6 7 public IProduct GetProduct() 8 { 9 switch (prodNo) //根据产品标识生产产品 10 { 11 default: 12 return new ProductA(); 13 case 1: 14 return new ProductA(); 15 case 2: 16 return new ProductB(); 17 } 18 19 } 20 21 22 } 23 24 //产品A 25 class ProductA: IProduct 26 { 27 //产品属性 28 //...... 29 } 30 31 //产品B 32 class ProductB : IProduct 33 { 34 //产品属性 35 //...... 36 } 37 //产品接口 38 interface IProduct 39 { 40 //产品方法 41 //...... 42 }
那么大家看看这段简单工厂的例子,如果我现在问,这个会有什么问题,该如何回答呢?提示一下,如果说来了一个需求,增加一个产品C,该如何办?没错,简单工厂的问题就在于swich case(或者if else)。每当新增一种产品时,你都需要去维护工厂中的判断语句,造成的后果就是可能这个工厂类会非常非常长,各种判断全部挤在一起,给扩展和维护带来很多麻烦。说白了,你的产品和工厂还是没有完全解耦,绑定在一起的。所以,我们得到了第二个结论:简单工厂通过构造时传入的标识来生产产品,不同产品都在同一个工厂中生产,这种判断会随着产品的增加而增加,给扩展和维护带来麻烦。那么,如何解决这个问题呢?
你猜对了,工厂模式可以解决这个问题:
工厂模式
1 interface IFactory //工厂接口 2 { 3 IProduct GetProduct(); 4 } 5 6 //A工厂类 7 public class FactoryA: IFactory 8 { 9 IProduct productA; 10 public FactoryA() 11 { 12 this.productA = new ProductA(); 13 } 14 15 public IProduct GetProduct() //A工厂生产A产品 16 { 17 return this.productA; 18 } 19 } 20 21 //B工厂类 22 public class FactoryB : IFactory 23 { 24 IProduct productB; 25 public FactoryB() 26 { 27 this.productB = new ProductB(); 28 } 29 30 public IProduct GetProduct() //B工厂生产B产品 31 { 32 return this.productB; 33 } 34 } 35 36 //产品接口 37 public interface IProduct 38 { 39 //产品方法 40 //...... 41 } 42 43 //产品A 44 public class ProductA : IProduct 45 { 46 //产品属性 47 //...... 48 } 49 50 //产品B 51 public class ProductB : IProduct 52 { 53 //产品属性 54 //...... 55 }
仔细观察这段代码,在工厂模式中,已经将工厂类分开,不再将所有产品在同一工厂中生产,这样就解决了简单工厂中不停的switch case的问题。如果说来了一个C产品,那么我们只需要写一个C工厂和C产品,在调用时用C工厂生产C产品即可,A和B工厂和产品完全不受影响。OK,优化说完了,但是还是有问题。
问题在哪里呢?当业务需求是需要生产产品族的时候,工厂就不再适合了。举个栗子:我想生产三星的洗衣机和格力的洗衣机,两个都是洗衣机,但是品牌不同,这个叫产品等级结构。最近格力的产品好卖,我想去生产格力的产品,不管是洗衣机还是冰箱都可以,只要是格力的就行,这个叫做产品族。而工厂模式无法解决产品族和产品等级结构的问题。这就要用到抽象工厂模式了。
抽象工厂
1 //工厂接口,即抽象工厂 2 interface IFactory 3 { 4 IFridge CreateFridge(); 5 IAirCondition CreateAirCondition(); 6 } 7 8 9 //三星的工厂,生产三星的产品族 10 public class SamsungFactory : IFactory 11 { 12 13 public IAirCondition CreateAirCondition() 14 { 15 return new SamsungAirCondition(); //三星的工厂生产三星的空调 16 17 } 18 19 public IFridge CreateFridge() 20 { 21 return new SamsungFridge(); //三星的工厂生产三星的冰箱 22 } 23 } 24 25 //格力的工厂,生产格力的产品族 26 27 public class GreeFactry : IFactory 28 { 29 public IAirCondition CreateAirCondition() 30 { 31 return new GreeAirCondition(); //格力的工厂生产格力的空调 32 } 33 34 public IFridge CreateFridge() 35 { 36 return new GreeFridge(); //格力的工厂生产格力的冰箱 37 } 38 } 39 40 //冰箱产品接口 41 public interface IFridge 42 { 43 //冰箱产品接口 44 //冰箱的action 45 } 46 47 //空调接口 48 public interface IAirCondition 49 { 50 //空调产品接口 51 //空调的action 52 } 53 54 //三星的冰箱 55 public class SamsungFridge: IFridge 56 { 57 //三星冰箱的action和property 58 } 59 //格力的冰箱 60 public class GreeFridge : IFridge 61 { 62 //格力冰箱的action和property 63 } 64 65 //三星的空调 66 public class SamsungAirCondition : IAirCondition 67 { 68 //三星空调的action和property 69 } 70 //格力的空调 71 public class GreeAirCondition : IAirCondition 72 { 73 //格力空调的action和property 74 }
我们可以看到,三星这个工厂里面产三星空调和三星冰箱,这是一个产品族,而三星冰箱也是冰箱啊,所以它派生于冰箱这个产品。
在上面的代码中,都使用了接口来表达抽象工厂或者抽象产品,那么可以用抽象类吗?
从功能上说,完全可以,甚至可以用接口来定义行为,用抽象类来抽象属性。抽象类更加偏向于属性的抽象,而用接口更加偏向行为的规范与统一。使用接口有更好的可扩展性和可维护性,更加灵活实现松散耦合,所以编程原则中有一条是针对接口编程而不是针对类编程。