简单工厂模式,工厂方法模式,抽象工厂模式
本文使用C#和Vuejs对简单工厂模式,工厂方法模式,抽象工厂模式进行了描述
分类: 创建型模式
参见
简单工厂模式
定义
- 该模式又被称为静态工厂方法模式;
- 简单工厂模式是由一个工厂对象决定创建出哪一种产品的实例;
- 简单工厂模式就是可以根据传入的参数的不同,返回不同的对象;
- 设计模式中的工厂模式借鉴了现实生活中工厂的概念。
示例
// 抽象汽车类, 也可以是接口public abstract class Car { public string Type { get; set;}}// 特斯拉public class Tesla: Car { public Tesla () { this.Type = "电动力车"; Console.Writeline("生产特斯拉电动汽车"); }}// 奔驰public class Benz: Car { public Benz () { this.Type = "汽油动力车"; Console.WriteLine("生产奔驰汽车"); }}// 工厂public class CarFactory{ // 静态工厂方法 public static Car Build(string carName) { Car car = null; if ("Tesla" == carName) { car = new Tesla(); } else if ("Benz" == carName) { car = new Benz(); } else { Console.WriteLine("没找到要生产的汽车Name"); } return car; }}// 消费者public class Customer{ public static void Main(String[] args) { CarFactory.Build("Benz"); CarFactory.Build("Tesla"); CarFactory.Build("Audi"); }}
JavaScript 示例
var CarFactory = (function () { var Car = function (carName, carType) { this.CarName = carName; this.CarType = carType; }; return function (carName, carType) { return new Car(carName, carType); }})();// 消费var audi = new CarFactory("Audi", "汽油车");var benz = new CarFactory("Benz", "汽油车");var tesla = new CarFactory("Tesla", "电动车");
Vuejs 示例
优点
- 将类实例化的操作与“使用”操作分离开,让使用者不用知道具体参数就可以实例化出所需要的“产品”类,从而避免了在客户端(消费者)代码中显式指定,实现了解耦;也就是说,使用者可以直接消费产品而无需知道其生产的细节
- 把初始化实例时的工作放到工厂里进行,使代码更容易维护;
- 更符合面向对象的原则 -> 面向接口编程;
缺点
- 如果需要新的产品,只能加if-else或者Switch加case,也就是硬编码,违反了开闭原则,对维护和扩展不够友好,所以一般使用在条件不多变化不大的情况下。
- 工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响;
- 简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构;
使用场景
- 工厂类负责创建的对象比较少,不会造成工厂方法中的业务逻辑太过复杂
- 客户端只知道传入工厂类的参数,对于如何创建对象并不关心
工厂方法模式
定义
工厂方法模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现
示例
// 抽象汽车类, 也可以是接口public abstract class Car { public string Type { get; set;}}// 特斯拉public class Tesla: Car { public Tesla () { this.Type = "电动力车"; Console.Writeline("生产特斯拉电动汽车"); }}// 奔驰public class Benz: Car { public Benz () { this.Type = "汽油动力车"; Console.WriteLine("生产奔驰汽车"); }}// 工厂接口public interface ICarFactory{ public Car Build();}public class BenzFactory: ICarFactory{ public Car Build() { return new Benz(); }}public class TeslaFactory: ICarFactory{ public Car Build() { return new Tesla(); }}// 消费者public class Customer{ public static void Main(String[] args) { ICarFactory factory = null; Car teslaCar = null; Car benzCar = null; // 生产 Tesla factory = new TeslaFactory(); teslaCar = facotry.Build(); // 生产 Benz factory = new BenzFactory(); benzCar = factory.Build(); }}
Vuejs 示例
优点
- 符合开闭原则,容易扩展,新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可;
符合单一职责原则,每个具体工厂类只负责创建对应的产品;
缺点
- 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度;
- 虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
一个具体工厂只能创建一种具体产品;
讨论
既然是一个工厂对应一个目标对象,那我还要工厂干嘛,我直接 new 我的目标对象不就可以了
思考以下场景:
假如我有三个对象Car car1 = new Tesla();Car car2 = new Tesla();Car car3 = new Tesla();
那么此时我不想要 Tesla 了,我想换成Benz,此时是不是需要修改三处(可能分散在系统各个类库里),这个时候工厂方法模式的好处在哪里体现呢?
CarFactory factory = new TeslaFactory();Car car1 = factory.build();Car car2 = factory.build();Car car3 = factory.build();
这个时候,要换成Benz, 就修改
CarFactory factory = new BenzFactory();
一处就可以了。
别忘了,你在加 Teacher 的时候,是符合开闭原则的,而简单工厂模式是不符合的。
使用场景
- 客户端不知道它所需要的对象的类。客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;
- 抽象工厂类通过其子类来指定创建哪个对象。对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象
抽象工厂模式
定义
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类;
抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品; 抽象工厂模式主要能实现很多不同的类的修改。
示例
// 产品抽象接口public interface IProduct {}// 车 抽象接口public interface ICar: IProduct {}// 自行车 抽象接口public interface IBike: IProduct {}// 具体产品 - 特斯拉电动车public class TeslaCar: ICar { public TeslaCar () { Console.WriteLine("生产 Tesla 电动车"); }}// 具体产品 - 特斯拉自行车public class TeslaBike: IBike { public TeslaBike () { Console.WriteLine("生产 Tesla 自行车"); }}// 具体产品 - 奔驰汽车public class BenzCar: ICar { public BenzCar () { Console.WriteLine("生产 奔驰 汽油车"); }}// 具体产品 - 奔驰自行车public class BenzBike: IBike { public BenzBike () { Console.WriteLine("生产 奔驰 自行车"); }}// 抽象工厂public interface IProductFactory{ ICar BuildCar (); IBike BuildBike ();}// 具体工厂类 - 特斯拉工厂public class TeslaProductFactory: IProductFactory{ public ICar BuildCar () { return new TeslaCar(); } public IBike BuildBike () { return new TeslaBike(); }}// 具体工厂类 - 奔驰工厂public class BenzProductFactory: IProductFactory{ public ICar BuildCar () { return new BenzCar(); } public IBike BuildBike () { return new BenzBike(); } }// 消费者public class Customer{ public static void Main() { IProductFactory factory = null; factory = new TeslaProductFactory(); var car = factory.BuildCar(); var bike = factory.BuildBike(); /* 当要修改产品,比如我们不要特斯啦的产品了,我要奔驰的,那么就只需要改动一个地方 factory = new TeslaProductFactory(); => factory = new BenzProductFactory(); 其他地方不需要修改 */ }}
结果
生产 Tesla 电动车生产 Tesla 自行车生产 奔驰 汽油车生产 奔驰 自行车
Vuejs 示例
讨论
每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式针对的是多个产品等级结构。有多少个产品等级结构,就会在工厂角色中发现多少个工厂方法。每一个产品等级结构中有多少个具体的产品,就有多少个产品族,也就会在工厂等级结构中发现多少个具体工厂。总结一下我认为可以应用到抽象工厂模式的实际例子:
- 两种产品:特斯拉和奔驰,两种产品等级:车和自行车
- 两种产品:PC和MAC,两种产品等级:RAM,CPU
- 两种产品:水果和蔬菜,两种产品等级:南方特产,北方特产
- 两种产品:男人和女人,三种产品等级:黄种人,黑人,白人
就类似这种结构的对象关系都可以用抽象工厂模式来构造。。。。。
优点
- 分离接口和实现
切换产品族变的异常方便
缺点
如果需要给整个产品族添加一个新的产品,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类;比如增加一个滑板车(特斯拉滑板车,奔驰滑板车)
使用场景
为创建一组对象提供了一种解决方案
总结
- 简单工厂模式 简单工厂类负责了所有产品的创建逻辑,当需要引进一个新的产品时,就不得不修改工厂类的产品创建逻辑,当产品类型较多时有可能造成工厂类的产品创建逻辑过于复杂,不利于系统的维护和扩展
- 工厂方法模式 对简单工厂模式的设计优化,简单工厂模式中如果新增一类产品,就需要修改工厂静态方法的产品创建逻辑,而使用工厂方法模式,只需要新扩展出一个新的工厂子类和产品类,使系统具有了良好的扩展性和维护性
- 抽象工厂模式 为创建一组(一族)对象提供了一种解决方案,与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一组(一族)产品。
本文完。
参考资料: