工厂模式 - java的三种工厂模式
简单工厂模式
首先举一个例子:
我们现在开了一家饭馆:
package com.wangcp.factoryModel.common;
/**
* 餐馆
* @author wangcp
* @date 2022/01/12 14:03
* @return
*/
public interface Restaurant {
// 做菜
void cook();
}
然后呢我们的大厨可以做三种菜,还有一句潇洒的抱怨:
package com.wangcp.factoryModel.common;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 炒肉
* @author wangcp
* @date 2022/01/12 14:04
**/
public class Meet implements Restaurant {
@Override
public void cook() {
System.out.println("炒一盘肉片");
}
}
package com.wangcp.factoryModel.common;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 烧鱼
* @author wangcp
* @date 2022/01/12 14:05
**/
public class Fish implements Restaurant {
@Override
public void cook() {
System.out.println("来盘糖醋鲤鱼!");
}
}
package com.wangcp.factoryModel.common;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 鸭子
* @author wangcp
* @date 2022/01/12 14:06
**/
public class Duck implements Restaurant {
@Override
public void cook() {
System.out.println("来份老鸭粉丝汤");
}
}
下面客人进场,开始点餐:
package com.wangcp.factoryModel.model1;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 客户类
* @author wangcp
* @date 2022/01/12 14:11
**/
public class Customer {
public static void main(String[] args) {
Restaurant restaurant = new Meet();
restaurant.cook();
Restaurant restaurant1 = new Duck();
restaurant1.cook();
}
}
我们观察上面的代码,虽然很好的完成了任务,但是,我们的三个实现类和和借口紧密的绑定到了一起,这意味着我们的代码耦合出现严重问题,不利于以后的维护,试想顾客点餐需要与后厨大厨直接接触,这肯定是一个不好的体验,那么我们就需要一个传菜员或者一个点餐系统:
package com.wangcp.factoryModel.model1;
import com.wangcp.factoryModel.common.Duck;
import com.wangcp.factoryModel.common.Fish;
import com.wangcp.factoryModel.common.Meet;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 服务员类
* @author wangcp
* @date 2022/01/12 14:20
**/
public class Waiter {
public static final int MENU_MEET = 1; //炒肉
public static final int MENU_FISH = 2; //烧鱼
public static final int MENU_DUCK = 3; //鸭子
public static Restaurant getMenu(int menuType){
switch (menuType){
case MENU_MEET:
return new Meet("三分熟");
case MENU_FISH:
return new Fish();
case MENU_DUCK:
return new Duck();
default:
return new Rubbish();
}
}
}
这个时候,客人再点餐的话就可以直接找到该服务员,让他负责跟后厨沟通:
package com.wangcp.factoryModel.model1;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 客户类
* @author wangcp
* @date 2022/01/12 14:11
**/
public class Customer {
public static void main(String[] args) {
Restaurant restaurant = Waiter.getMenu(Waiter.MENU_DUCK);
restaurant.cook();
}
}
这个时候,我们只需要getMeut方法直接告知我们需要什么就行了。
特点
- 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
- create()方法通常是静态的,所以也称之为静态工厂。
缺点
- 扩展性差(我想增加一种面条,除了新增一个面条产品类,还需要修改工厂类方法)
- 不同的产品需要不同额外参数的时候 不支持。
多方法静态工厂(常用)
我们知道,上面的简单工厂模式有一个缺点是不同的产品需要不同的额外参数的时候,是不支持的,
而且如果使用时传递的type、Class出错,将不能得到正确的对象,容错率不高。
而多方法的工厂模式为不同产品,提供不同的生产方法,使用时 需要哪种产品就调用该种产品的方法,使用方便、容错率高。
同样是一接口:
package com.wangcp.factoryModel.common;
/**
* 餐馆
* @author wangcp
* @date 2022/01/12 14:03
* @return
*/
public interface Restaurant {
// 做菜
void cook();
}
三个实现类(产品):
package com.wangcp.factoryModel.common;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 炒肉
* @author wangcp
* @date 2022/01/12 14:04
**/
public class Meet implements Restaurant {
String param;
public Meet(String param){
this.param = param;
}
@Override
public void cook() {
System.out.println("炒一盘肉片" + param);
}
}
package com.wangcp.factoryModel.common;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 鸭子
* @author wangcp
* @date 2022/01/12 14:06
**/
public class Duck implements Restaurant {
@Override
public void cook() {
System.out.println("来份老鸭粉丝汤");
}
}
package com.wangcp.factoryModel.common;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 烧鱼
* @author wangcp
* @date 2022/01/12 14:05
**/
public class Fish implements Restaurant {
@Override
public void cook() {
System.out.println("来盘糖醋鲤鱼!");
}
}
工厂类:
package com.wangcp.factoryModel.model2;
import com.wangcp.factoryModel.common.Duck;
import com.wangcp.factoryModel.common.Fish;
import com.wangcp.factoryModel.common.Meet;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 工厂类
* @author wangcp
* @date 2022/01/12 14:35
**/
public class CookFactory {
public static Restaurant createMeet(String param){
return new Meet(param);
}
public static Restaurant createFish(){
return new Fish();
}
public static Restaurant createDuck(){
return new Duck();
}
}
使用:
package com.wangcp.factoryModel.model2;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 测试类
* @author wangcp
* @date 2022/01/12 14:38
**/
public class TestMain {
public static void main(String[] args) {
Restaurant meetCooker = CookFactory.createMeet("三分熟");
meetCooker.cook();
Restaurant duckCooker = CookFactory.createDuck();
duckCooker.cook();
Restaurant fishCooker = CookFactory.createFish();
fishCooker.cook();
}
}
工厂方法模式
工厂方法模式是把普通工厂就是把简单工厂中具体的工厂类,划分成两层:抽象工厂层+具体的工厂子类层。
为了解决简单工厂的问题,程序员们又想出来一个新的办法,就是设计一个工厂的接口,你想要什么东西,就写个类继承于这个工厂,这样就不用修改什么,直接添加就行了。就相当于,我这个工厂是用来生产鞋子的,而要什么品牌的鞋子具体分到了每个车间,如果新多了一种品牌的鞋子,直接新增一个车间就行了。那么问题又来了,如果想要生产衣服怎么办?
还是那个Restanrant接口和其三个实现类(产品)这里不再重复贴出了,我们要看工厂类的实现
抽象工厂类:
package com.wangcp.factoryModel.model3;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 抽象工厂类
* @author wangcp
* @date 2022/01/12 17:50
**/
public abstract class CookFactory2 {
abstract Restaurant createRestaurant();
}
其实现类(获取具体产品)
package com.wangcp.factoryModel.model3;
import com.wangcp.factoryModel.common.Duck;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 鸭子工厂类
* @author wangcp
* @date 2022/01/12 17:52
**/
public class DuckFactory extends CookFactory2 {
@Override
public Restaurant createRestaurant() {
return new Duck();
}
}
package com.wangcp.factoryModel.model3;
import com.wangcp.factoryModel.common.Fish;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 鱼工厂类
* @author wangcp
* @date 2022/01/12 17:54
**/
public class FishFactory extends CookFactory2{
@Override
Restaurant createRestaurant() {
return new Fish();
}
}
开始使用:
package com.wangcp.factoryModel.model3;
import com.wangcp.factoryModel.common.Restaurant;
/**
* 测试类
* @author wangcp
* @date 2022/01/12 17:55
**/
public class Test2 {
public static void main(String[] args) {
Restaurant meet = new DuckFactory().createRestaurant();
meet.cook();
Restaurant fish = new FishFactory().createRestaurant();
fish.cook();
}
}
介绍
定义
工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。
主要作用
将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一个类。
解决的问题
工厂一旦需要生产新产品就需要修改工厂类的方法逻辑,违背了“开放 - 关闭原则
1.即简单工厂模式的缺点
2.之所以可以解决简单工厂的问题,是因为工厂方法模式把具体产品的创建推迟到工厂类的子类(具体工厂)中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式在添加新产品的时候就不修改工厂类逻辑而是添加新的工厂子类,符合开放封闭原则,克服了简单工厂模式中缺点
模式原理
UML类图
模式组成
组成(角色) | 关系 | 作用 |
---|---|---|
抽象产品(Product) | 具体产品的父类 | 描述具体产品的公共接口 |
具体产品(Concrete Product) | 抽象产品的子类;工厂类创建的目标类 | 描述生产的具体产品 |
抽象工厂(Creator) | 具体工厂的父类 | 描述具体工厂的公共接口 |
具体工厂(Concrerte Creator) | 抽象工厂的子类;被外界调用 | 描述具体工厂;实现FactoryMethod工厂方法创建产品的实例 |
具体步骤
- 1.创建抽象工厂类,定义具体工厂的公共接口;
- 2.创建抽象产品类 ,定义具体产品的公共接口;
- 3.创建具体产品类(继承抽象产品类) & 定义生产的具体产品;
- 4.创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
- 5.外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
优点
-
更符合开-闭原则
新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可
简单工厂模式需要修改工厂类的判断逻辑
-
符合单一职责原则
每个具体工厂类只负责创建对应的产品
简单工厂中的工厂类存在复杂的switch逻辑判断
-
不使用静态工厂方法,可以形成基于继承的等级结构。
简单工厂模式的工厂类使用静态工厂方法
总结:工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。