大家好,又见面了,我是你们的朋友全栈君。
首先举一个例子:
我们现在开了一家饭馆:
然后呢我们的大厨可以做三种菜,还有一句潇洒的抱怨:
下面客人进场,开始点餐:
我们观察上面的代码,虽然很好的完成了任务,但是,我们的三个实现类和和借口紧密的绑定到了一起,这意味着我们的代码耦合出现严重问题,不利于以后的维护,试想顾客点餐需要与后厨大厨直接接触,这肯定是一个不好的体验,那么我们就需要一个传菜员或者一个点餐系统:
这个时候,客人再点餐的话就可以直接找到该服务员,让他负责跟后厨沟通:
这个时候,我们只需要getMeut方法直接告知我们需要什么就行了。
1 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
2 create()方法通常是静态的,所以也称之为静态工厂。
1 扩展性差(我想增加一种面条,除了新增一个面条产品类,还需要修改工厂类方法)
2 不同的产品需要不同额外参数的时候 不支持。
我们知道,上面的简单工厂模式有一个缺点是不同的产品需要不同的额外参数的时候,是不支持的,
而且如果使用时传递的type、Class出错,将不能得到正确的对象,容错率不高。
而多方法的工厂模式为不同产品,提供不同的生产方法,使用时 需要哪种产品就调用该种产品的方法,使用方便、容错率高。
请看下面的例子。
同样是一接口:
三个实现类(产品):
工厂类:
使用 :
工厂方法模式是把普通工厂就是把简单工厂中具体的工厂类,划分成两层:抽象工厂层+具体的工厂子类层。
为了解决简单工厂的问题,程序员们又想出来一个新的办法,就是设计一个工厂的接口,你想要什么东西,就写个类继承于这个工厂,这样就不用修改什么,直接添加就行了。就相当于,我这个工厂是用来生产鞋子的,而要什么品牌的鞋子具体分到了每个车间,如果新多了一种品牌的鞋子,直接新增一个车间就行了。那么问题又来了,如果想要生产衣服怎么办?
还是那个Restanrant接口和其三个实现类(产品)这里不再重复贴出了,我们要看工厂类的实现
抽象工厂类:
其实现类(获取具体产品)
开始享用:
通过上面的一个代码案例我们大概的了解了一下工厂方法模式,下面我们具体了解。
在上文提到的最易懂的设计模式系列解析:简单工厂模式,发现简单工厂模式存在一系列问题:
为了解决上述的问题,我们又使用了一种新的设计模式:工厂方法模式。
1.1 定义
工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。
1.2 主要作用
将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一个类。
1.3 解决的问题
工厂一旦需要生产新产品就需要修改工厂类的方法逻辑,违背了“开放 – 关闭原则
2.1 UML类图
2.2 模式组成
组成(角色) | 关系 | 作用 |
---|---|---|
抽象产品(Product) | 具体产品的父类 | 描述具体产品的公共接口 |
具体产品(Concrete Product) | 抽象产品的子类;工厂类创建的目标类 | 描述生产的具体产品 |
抽象工厂(Creator) | 具体工厂的父类 | 描述具体工厂的公共接口 |
具体工厂(Concrete Creator) | 抽象工厂的子类;被外界调用 | 描述具体工厂;实现FactoryMethod工厂方法创建产品的实例 |
2.3 使用步骤
步骤1: 创建抽象工厂类,定义具体工厂的公共接口; 步骤2: 创建抽象产品类 ,定义具体产品的公共接口; 步骤3: 创建具体产品类(继承抽象产品类) & 定义生产的具体产品; 步骤4:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法; 步骤5:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
接下来我用一个实例来对工厂方法模式进行更深一步的介绍。
3.1 实例概况
3.2 使用步骤
步骤1: 创建抽象工厂类,定义具体工厂的公共接口
abstract class Factory{
public abstract Product Manufacture();
}
步骤2: 创建抽象产品类 ,定义具体产品的公共接口;
abstract class Product{
public abstract void Show();
}
步骤3: 创建具体产品类(继承抽象产品类), 定义生产的具体产品;
//具体产品A类
class ProductA extends Product{
@Override
public void Show() {
System.out.println("生产出了产品A");
}
}
//具体产品B类
class ProductB extends Product{
@Override
public void Show() {
System.out.println("生产出了产品B");
}
}
步骤4:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
//工厂A类 - 生产A类产品
class FactoryA extends Factory{
@Override
public Product Manufacture() {
return new ProductA();
}
}
//工厂B类 - 生产B类产品
class FactoryB extends Factory{
@Override
public Product Manufacture() {
return new ProductB();
}
}
步骤5:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
//生产工作流程
public class FactoryPattern {
public static void main(String[] args){
//客户要产品A
FactoryA mFactoryA = new FactoryA();
mFactoryA.Manufacture().Show();
//客户要产品B
FactoryB mFactoryB = new FactoryB();
mFactoryB.Manufacture().Show();
}
}
结果:
生产出了产品A
生产出了产品C
总结:工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。
在了解了优缺点后,我总结了工厂方法模式的应用场景:
2018.03.10 15:53 1095浏览
字号
1、介绍
意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
主要解决:主要解决接口选择的问题。
何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
如何解决:在一个产品族里面,定义多个产品。每个具体的工厂负责一个产品族。抽象工厂的返回值为最高级抽象产品。
关键代码:在一个工厂里聚合多个同类产品(在同一个产品族中)。
应用实例:举一个衣服与衣柜的例子。家里边,有男装(产品族,其中包含休闲男装和商务男装)、女装(产品族,其中包含休闲女装和商务女装)。商务女装、商务男装、时尚女装、时尚男装,这些都是具体产品。男装专门放在男衣柜(具体工厂)中,女装专门放在女衣柜(具体工厂)中。当我们需要拿衣服时候,从衣柜(抽象工厂)中获取。
所以抽象工厂,非常适合解决两个维度的组合产品的构造问题,取其中一个维度作为产品族,另外一个维度作为产品族中具体的多个产品。
优点:能够从多个产品族的多个产品中,简洁的获取想要的具体产品。解决了工厂模式中的不符合开闭原则的问题(增加新的产品时候,不修改工厂,而是增加工厂)。
缺点:产品族扩展比较困难,要增加一个系列的某一产品,要增加具体的产品类,还要增加对应的工厂类(或者修改对应产品族的工厂类)。
注意事项:产品族难扩展,产品等级易扩展。
2、案例
2.1、背景
还是举买车的例子。
某客户想要购买一辆车,他要联系4S店,首先得有4S店(抽象工厂)的电话。
客户上网查询(建造工厂),发现了宝马4S店(具体工厂)的电话和奔驰4S店(具体工厂)的电话。
客户拨通了宝马4S店的电话(获取具体工厂),发现目前店里可以提供(生产)多款车型(具体产品)供客户选择(BMW 320、BMW 530,BMW 740)。
客户拨通了奔驰4S店的电话(获取具体工厂),发现目前店里可以提供(生产)多款车型(具体产品)供客户选择(BenzC200、BenzE300)。
2.2、实现
/**
* 最高级抽象产品,用于抽象工厂的建造方法的返回值
*/
public abstract class Car
{
abstract void drive();
}
/**
* 抽象产品
*/
public abstract class BMWCar extends Car
{
}
/**
* 具体产品BMW320
*/
public class BMW320 extends BMWCar
{
public void drive()
{
System.out.println("BMW320,运动酷炫。");
}
}
/**
* 具体产品BMW530
*/
public class BMW530 extends BMWCar
{
public void drive()
{
System.out.println("BMW530,时不我待。");
}
}
/**
* 具体产品BMW740
*/
public class BMW740 extends BMWCar
{
public void drive()
{
System.out.println("BMW740,高端商务。");
}
}
/**
* 抽象产品
*/
public abstract class BenzCar extends Car
{
}
/**
* 具体产品C200
*/
public class BenzC200 extends BenzCar
{
public void drive()
{
System.out.println("BenzC200,实惠有面");
}
}
/**
* 具体产品E300
*/
public class BenzE300 extends BenzCar
{
public void drive()
{
System.out.println("BenzE300,商务气派");
}
}
/**
* 奔驰工厂,覆盖所有奔驰车型的构造方法
*/
public class BenzFactory extends AbstractFactory
{
public Car getCar(String type) throws ClassNotFoundException,
IllegalAccessException, InstantiationException
{
Class cl = Class.forName(type);
return (BenzCar)cl.newInstance();
}
}
/**
* 宝马工厂,覆盖所有宝马车型的构造方法
*/
public class BMWFactory extends AbstractFactory
{
public Car getCar(String type) throws ClassNotFoundException,
IllegalAccessException, InstantiationException
{
Class cl = Class.forName(type);
return (BMWCar)cl.newInstance();
}
}
public abstract class AbstractFactory
{
public abstract Car getCar(String type) throws ClassNotFoundException,
IllegalAccessException, InstantiationException;
}
/**
* 超级工厂类,建造工厂的工厂
*/
public class FactoryProducer
{
public static AbstractFactory getFactory(String type)
throws IllegalAccessException, InstantiationException, ClassNotFoundException
{
Class cl = Class.forName(type);
System.out.println("创建工厂"+type);
return (AbstractFactory)cl.newInstance();
}
}
/**
* 验证
*/
public class Demo
{
public static void main(String[] args) throws IllegalAccessException,
InstantiationException, ClassNotFoundException
{
AbstractFactory abstractFactory = FactoryProducer.getFactory("BMWFactory");
Car bmwCar = abstractFactory.getCar("BMW320");
bmwCar.drive();
Car bmwCar1 = abstractFactory.getCar("BMW530");
bmwCar1.drive();
Car bmwCar2 = abstractFactory.getCar("BMW740");
bmwCar2.drive();
AbstractFactory abstractFactory1 = FactoryProducer.getFactory("BenzFactory");
Car benzCar = abstractFactory1.getCar("BenzC200");
benzCar.drive();
Car benzCar1 = abstractFactory1.getCar("BenzE300");
benzCar1.drive();
}
}
运行结果如下如所示:
3、总结
抽象工厂模式非常针对2个维度描述的产品的构造问题。取其中一个维度作为产品族(也就是对应一个具体工厂),另外一个维度作为产品族下的具体产品。从这个角度说,抽象工厂模式是在工厂模式基础上,做了一个维度的升级。
举例,比如商务男装,商务女装,时尚男装,时尚女装的选择问题。取男装为一个产品族,对应一个工厂;取女装作为一个产品族,对应一个工厂。每个工厂中会生产多种类型(商务或者时尚)的衣服。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/156675.html原文链接:https://javaforall.cn