设计模式——工厂模式
一、多方法静态工厂
多方法的工厂模式为不同产品,提供不同的生产方法,使用时 需要哪种产品就调用该种产品的方法,使用方便、容错率高。
设计一个餐厅接口:
1 public interface Restaurant { 2 public void cook(); 3 }
三个实现类(产品):
1 public class Meet implements Restaurant{ 2 String param; 3 public Meet(String param) { 4 this.param = param; 5 } 6 @Override 7 public void cook() { 8 System.out.println("来盘小炒肉!" + param); 9 } 10 }
1 public class Fish implements Restaurant{ 2 @Override 3 public void cook() { 4 System.out.println("来盘鲱鱼罐头!"); 5 } 6 }
1 public class Duck implements Restaurant{ 2 @Override 3 public void cook() { 4 System.out.println("来只北京烤鸭!"); 5 } 6 }
工厂类:
1 public class CookFactory { 2 3 public static Restaurant createMeet(String param) { 4 return new Meet(param); 5 } 6 7 public static Restaurant createFish() { 8 return new Fish(); 9 } 10 11 public static Restaurant createDuck() { 12 return new Duck(); 13 } 14 }
测试类:
1 public class Test { 2 3 public static void main(String[] args) { 4 5 Restaurant meetCooker = CookFactory.createMeet("七分熟"); 6 meetCooker.cook(); 7 Restaurant fishCooker = CookFactory.createFish(); 8 fishCooker.cook(); 9 Restaurant duckCooker = CookFactory.createDuck(); 10 duckCooker.cook(); 11 } 12 }
二、工厂方法模式
工厂方法模式是把普通工厂就是把简单工厂中具体的工厂类,划分成两层:抽象工厂层+具体的工厂子类层。
为了解决简单工厂的问题,程序员们又想出来一个新的办法,就是设计一个工厂的接口,你想要什么东西,就写个类继承于这个工厂,这样就不用修改什么,直接添加就行了。就相当于,我这个工厂是用来生产鞋子的,而要什么品牌的鞋子具体分到了每个车间,如果新多了一种品牌的鞋子,直接新增一个车间就行了。那么问题又来了,如果想要生产衣服怎么办?
还是那个Restanrant接口和其三个实现类(产品)这里不再重复贴出了,我们要看工厂类的实现
抽象工厂类:
1 public abstract class CookFactory2 { 2 public abstract Restaurant createRestaurant(); 3 }
其实现类(获取具体产品):
1 public class DuckFactory extends CookFactory2{ 2 @Override 3 public Restaurant createRestaurant() { 4 return new Duck(); 5 } 6 }
1 public class FishFactory extends CookFactory2{ 2 @Override 3 public Restaurant createRestaurant() { 4 return new Fish(); 5 } 6 }
测试类:
1 public class Test2 { 2 public static void main(String[] args) { 3 Restaurant meet = new DuckFactory().createRestaurant(); 4 meet.cook(); 5 Restaurant fish = new FishFactory().createRestaurant(); 6 fish.cook(); 7 } 8 }
具体说明工厂方法模式:
1. 介绍
1.1 定义
工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。
1.2 主要作用
将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一个类。
1.3 解决的问题
工厂一旦需要生产新产品就需要修改工厂类的方法逻辑,违背了“开放-关闭原则”。
即简单工厂模式的缺点:
- 之所以可以解决简单工厂的问题,是因为工厂方法模式把具体产品的创建推迟到工厂类的子类(具体工厂)中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式在添加新产品的时候就不修改工厂类逻辑而是添加新的工厂子类,符合开放封闭原则,克服了简单工厂模式中缺点。
2. 模式原理
2.1 UML类图
2.2 模式组成
组成(角色) | 关系 | 作用 |
抽象产品(Product) | 具体产品的父类 | 描述具体产品的公共接口 |
具体产品(Concrete Product) | 抽象产品的子类;工厂类创建的目标类 | 描述生产的具体产品 |
抽象工厂(Creator) | 具体工厂的父类 | 描述具体工厂的公共接口 |
具体工厂(Concrete Creator) | 抽象工厂的子类;被外界调用 | 描述具体工厂;实现FactoryMethod工厂方法创建产品的实例 |
2.3 使用步骤
步骤1: 创建抽象工厂类,定义具体工厂的公共接口;
步骤2: 创建抽象产品类 ,定义具体产品的公共接口;
步骤3: 创建具体产品类(继承抽象产品类) && 定义生产的具体产品;
步骤4:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
步骤5:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例。
3. 优点
- 更符合开-闭原则
新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可;
- 符合单一职责原则
每个具体工厂类只负责创建对应的产品;
- 不使用静态工厂方法,可以形成基于继承的等级结构
总结:工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。
4. 缺点
- 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度;
- 虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
- 一个具体工厂只能创建一种具体产品。
6. 应用场景
- 当一个类不知道它所需要的对象的类时
在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可; - 当一个类希望通过其子类来指定创建对象时
在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。 - 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。
三、抽象工厂模式
1、介绍
意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
主要解决:主要解决接口选择的问题。
何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
如何解决:在一个产品族里面,定义多个产品。每个具体的工厂负责一个产品族。抽象工厂的返回值为最高级抽象产品。
关键代码:在一个工厂里聚合多个同类产品(在同一个产品族中)。
应用实例:举一个衣服与衣柜的例子。家里边,有男装(产品族,其中包含休闲男装和商务男装)、女装(产品族,其中包含休闲女装和商务女装)。商务女装、商务男装、时尚女装、时尚男装,这些都是具体产品。男装专门放在男衣柜(具体工厂)中,女装专门放在女衣柜(具体工厂)中。当我们需要拿衣服时候,从衣柜(抽象工厂)中获取。
优点:能够从多个产品族的多个产品中,简洁的获取想要的具体产品。解决了工厂模式中的不符合开闭原则的问题(增加新的产品时候,不修改工厂,而是增加工厂)。
缺点:产品族扩展比较困难,要增加一个系列的某一产品,要增加具体的产品类,还要增加对应的工厂类(或者修改对应产品族的工厂类)。
参考链接:https://blog.csdn.net/qq564425/article/details/81082242?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param