浅谈简单工厂,工厂方法,抽象工厂的使用
前言
这几天了解了工厂模式,自己也整理下思路,任何一种模式的出现都是为了让我们的程序有更好的可扩展性,工厂模式也不例外。
简单工厂
在实际的代码coding中我们在创建对象(也就是实例化一个类)的时候往往需要new class()这样来操作。举个例子:
这是项目结构
//这是一个中国人的类
public class ChinesePepole { public void Show() { Console.WriteLine("I'm a {0}", this.GetType().Name); } }
当我们在前端(这里是在控制台)需要使用的时候就一般会这样做
1 static void Main(string[] args) 2 { 3 //创建一个中国人 4 ChinesePepole chinesePepole = new ChinesePepole(); 5 chinesePepole.Show(); 6 7 }
这样做显然不利于程序扩展,比如这里创建对象我们要换成一个美国人,日本人我们要不断的去修改代码。
1 static void Main(string[] args) 2 { 3 //创建一个中国人 4 ChinesePepole chinesePepole = new ChinesePepole(); 5 chinesePepole.Show(); 6 //创建一个美国人 7 AmericanPeople americanPeople = new AmericanPeople(); 8 americanPeople.Show(); 9 //创建一个日本人 10 JapanesePeople japanesePeople = new JapanesePeople(); 11 japanesePeople.Show(); 12 13 Console.ReadLine(); 14 15 }
因为违背了面向对象设计的依赖倒置原则,这里解释下什么是依赖倒置原则
依赖倒置原则
A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。
B.抽象不应该依赖于具体实现,具体实现应该依赖于抽象。
1 /// <summary> 2 /// 把人进行抽象 定义一个接口 3 /// </summary> 4 public interface IPeople 5 { 6 void Show(); 7 } 8 9 /// <summary> 10 /// 具体的人 中国人 11 /// </summary> 12 public class ChinesePepole : IPeople 13 { 14 public void Show() 15 { 16 Console.WriteLine("I'm a {0}", this.GetType().Name); 17 } 18 } 19 20 /// <summary> 21 /// 具体的人 美国人 22 /// </summary> 23 public class AmericanPeople : IPeople 24 { 25 public void Show() 26 { 27 Console.WriteLine("I'm a {0}", this.GetType().Name); 28 } 29 } 30 31 /// <summary> 32 /// 具体的人 日本人 33 /// </summary> 34 public class JapanesePeople : IPeople 35 { 36 public void Show() 37 { 38 Console.WriteLine("I'm a {0}", this.GetType().Name); 39 } 40 }
这时我就可以通过接口来创建对象了
1 static void Main(string[] args) 2 { 3 4 //创建一个中国人 5 IPeople chinesePepole = new ChinesePepole(); 6 chinesePepole.Show(); 7 8 Console.ReadLine(); 9 10 }
这时虽然左边没有的具体的类名 ,但右边依然有new class()这样的细节,这时工厂就出现了,就是把实例化对象的过程交给工厂来处理。简单工厂代码如下:
1 public class Factory 2 { 3 public IPeople.IPeople GetPeople(PeopleType peopleType) 4 { 5 switch (peopleType) 6 { 7 case PeopleType.Chinese: 8 return new ChinesePepole(); 9 case PeopleType.American: 10 return new AmericanPeople(); 11 case PeopleType.Japanese: 12 return new JapanesePeople(); 13 default: 14 throw new Exception("没有可用的类"); 15 } 16 } 17 18 public enum PeopleType 19 { 20 Chinese, 21 American, 22 Japanese 23 } 24 }
上层调用
1 static void Main(string[] args) 2 { 3 Factory factory = new Factory(); 4 //创建一个中国人 5 IPeople.IPeople chinesePeople = factory.GetPeople(Factory.PeopleType.Chinese); 6 chinesePeople.Show(); 7 Console.ReadLine(); 8 }
简单工厂就是这样,调用工厂类根据上层传入的参数创建我们需要的实例类。
简单工厂的优点和缺点
优点:能够根据外界给定的信息自动去创建对象,上层没有具体创建类的细节,提高了程序的可扩展性
缺点:工厂类集中了所有实例的创建逻辑,程序中创建对象的细节并没有消失,我们只是转移了细节。如果要新增实体对象的创建还是要修改程序,违背了开-闭原则 (对扩展开放,对修改关闭)。
工厂方法
介绍:
工厂方法就是对上面的简单工厂进行升级,不让所有实例的创建逻辑都在一个工厂类中实现,具体的类交给具体的工厂去创建。
核心代码如下:
1 /// <summary> 2 /// 抽象工厂类 3 /// </summary> 4 public interface IFactory 5 { 6 IPeople.IPeople CreatePeople(); 7 }
1 /// <summary> 2 /// 具体工厂类: 用于创建中国人类 3 /// </summary> 4 public class ChineseFactory : IFactory 5 { 6 public IPeople.IPeople CreatePeople() 7 { 8 return new ChinesePepole(); 9 } 10 }
1 /// <summary> 2 /// 具体工厂类: 用于创建美国人类 3 /// </summary> 4 public class AmericanFactory:IFactory 5 { 6 public IPeople.IPeople CreatePeople() 7 { 8 return new People.AmericanPeople(); 9 } 10 }
//上层调用
static void Main(string[] args) { IFactory factory = new AmericanFactory(); IPeople.IPeople americanPeople = factory.CreatePeople(); americanPeople.Show(); Console.ReadLine(); }
工厂方法的优点和缺点
优点:具体的类交给具体的工厂去创建,符合开闭原则,如果再新建一个类,只需要新增对应的工厂类即可,不需要对代码进行修改。
缺点:代码多,新增了一个工厂类(呵呵)
抽象工厂
代码如下
抽象工厂代码
1 /// <summary> 2 /// 抽象工厂类 3 /// </summary> 4 public abstract class AbstractFactory 5 { 6 /// <summary> 7 /// 抽象方法:创建一个人 8 /// </summary> 9 /// <returns></returns> 10 public abstract AbstractPeople CreatePeople(); 11 12 /// <summary> 13 /// 抽象方法:创建一辆车 14 /// </summary> 15 /// <returns></returns> 16 public abstract AbstractCar CreateCar(); 17 }
具体工厂代码
1 /// <summary> 2 /// 具体工厂类 创建一个美国的工厂 3 /// </summary> 4 public class AmericanFactory : AbstractFactory 5 { 6 public override AbstractPeople CreatePeople() 7 { 8 return new AmericanPeople(); 9 } 10 11 public override AbstractCar CreateCar() 12 { 13 return new AmericanCar(); 14 } 15 } 16 17 /// <summary> 18 /// 具体工厂类 创建一个中国的工厂 19 /// </summary> 20 public class ChineseFactory : AbstractFactory 21 { 22 public override AbstractPeople CreatePeople() 23 { 24 return new ChinesePepole(); 25 } 26 27 public override AbstractCar CreateCar() 28 { 29 return new ChineseCar(); 30 } 31 }
具体实例的代码
1 /// <summary> 2 /// 具体的人 美国人 3 /// </summary> 4 public class AmericanPeople : AbstractPeople 5 { 6 /// <summary> 7 /// 国家 8 /// </summary> 9 public override string Country 10 { 11 get 12 { 13 return "美国"; 14 } 15 } 16 17 /// <summary> 18 /// 爱好 19 /// </summary> 20 public override string Like 21 { 22 get 23 { 24 return "打蓝球"; 25 } 26 } 27 28 /// <summary> 29 /// 肤色 30 /// </summary> 31 public override string Color 32 { 33 get 34 { 35 return "白种人"; 36 } 37 } 38 } 39 40 /// <summary> 41 /// 具体的人 中国人 42 /// </summary> 43 public class ChinesePepole :AbstractPeople 44 { 45 /// <summary> 46 /// 国家 47 /// </summary> 48 public override string Country 49 { 50 get 51 { 52 return "中国"; 53 } 54 } 55 56 /// <summary> 57 /// 爱好 58 /// </summary> 59 public override string Like 60 { 61 get 62 { 63 return "打乒乓球"; 64 } 65 } 66 67 /// <summary> 68 /// 肤色 69 /// </summary> 70 public override string Color 71 { 72 get 73 { 74 return "黄种人"; 75 } 76 } 77 } 78 79 /// <summary> 80 /// 具体的车 美国人的车 81 /// </summary> 82 public class AmericanCar : AbstractCar 83 { 84 /// <summary> 85 /// 类型 86 /// </summary> 87 public override string Type 88 { 89 get 90 { 91 return "商务车"; 92 } 93 } 94 95 /// <summary> 96 /// 颜色 97 /// </summary> 98 public override string Color 99 { 100 get 101 { 102 return "红色"; 103 } 104 } 105 } 106 107 /// <summary> 108 /// 具体的车 中国人的车 109 /// </summary> 110 public class ChineseCar : AbstractCar 111 { 112 /// <summary> 113 /// 类型 114 /// </summary> 115 public override string Type 116 { 117 get 118 { 119 return "越野车"; 120 } 121 } 122 123 /// <summary> 124 /// 颜色 125 /// </summary> 126 public override string Color 127 { 128 get 129 { 130 return "黑色"; 131 } 132 } 133 }
上层调用
1 static void Main(string[] args) 2 { 3 //CreateObject o = new CreateObject(new AmericanFactory()); 4 //o.ReadyInfo(); 5 CreateObject o = new CreateObject(new ChineseFactory()); 6 o.ReadyInfo(); 7 Console.ReadLine(); 8 } 9 10 /// <summary> 11 /// 创建对象 12 /// </summary> 13 public class CreateObject 14 { 15 private AbstractPeople people; 16 private AbstractCar car; 17 18 public CreateObject(AbstractFactory.AbstractFactory factory) 19 { 20 people = factory.CreatePeople(); 21 car = factory.CreateCar(); 22 } 23 24 public void ReadyInfo() 25 { 26 Console.WriteLine(string.Format("我是一个{0},来自{1},喜欢开着{2}的{3}。", 27 people.Color, 28 people.Country, 29 car.Color, 30 car.Type 31 )); 32 } 33 }
抽象工厂的优点/缺点:
优点:
抽象工厂模式封装了具体类的创建,
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象,
增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
缺点:增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类
总结:
简单工厂:一个工厂创建多个类 分支
工厂方法:一个工厂创建一个类
抽象工厂:一个工厂创建多个类 适用于产品簇