工厂模式
提出问题
问题案例
基础概述
是什么
工厂模式的好处就是解耦。
分类
- 简单/静态工厂模式
- 工厂方法模式
- 抽象工厂模式
应用
适用性
- 需要准备一个对象要做很多工作,而耦合在具体业务类当中并不恰当
当进行文件IO时,需要创建一个对象BufferedReader对象
1 | // 创建一个BufferedReader对象 |
- 当需要在很多地方使用到这个对象时,就会略显臃肿
- 同时,如果需要更换IO读写的类,如LineNumberReader,那么工作量相对很大
- 有时候需要判断具体new一个什么样的类
1 | public orderPizza(String type){ |
因此使用工厂模式,将对象创建委托给工厂
案例1
协作
结构
参与者
协作
- 类关系
- 逻辑关系
权衡
分类
结构
效果(优缺)
使用工厂模式的好处
- 让创建对象变得简单而且修改对象时能很方便呢
- 从面向对象的角度来看:我一个操作文件的类还要我会创建BufferReader是不是有点过分了?(职责没有分工好),交给工厂来创建对象这就很面向对象了!
专业一些即:
- 我们修改了具体的实现类,对客户端(调用方)而言是完全不用修改的。
- 如果我们使用new的方式来创建对象的话,那么我们就说:new出来的这个对象和当前客户端(调用方)耦合了!
- 也就是,当前客户端(调用方)依赖着这个
new
出来的对象!
- 也就是,当前客户端(调用方)依赖着这个
即使得解耦,低耦合
实现
实现步骤
案例1
相关模式
进阶
使用Lambda
反省总结
如何使用工厂模式
- 简单/静态工厂模式
- 工厂方法模式
- 抽象工厂模式
简单/静态工厂模式是在工厂方法模式上缩减,抽象工厂模式是在工厂方法模式上再增强。
工厂方法模式
Java3y每天写代码很无聊,想要买只宠物来陪陪自己。于是乎就去宠物店看宠物啦~
作为一间宠物店,号称什么宠物都有!于是乎,店主宣传的时候就说:我的宠物店什么宠物都有!
于是构建宠物的工厂就诞生了~
1 | // 号称什么宠物都有 |
当然了,主流的宠物得进货一些先放在店里充充门面,一些特殊的宠物就告诉顾客要时间进货~
- 所以,我们就有了构建猫和狗的工厂(继承着所有宠物的工厂)
猫工厂:
1 | // 继承着宠物工厂 |
狗工厂也是一样的:
1 | // 继承着宠物工厂 |
嗯,还有我们的实体类:猫、狗、动物(多态:猫和狗都是动物,可以直接用动物来表示了)
动物实体类:
1 | public abstract class Animal { |
猫实体类:
1 | public class Cat extends Animal { |
狗实体类:
1 | public class Dog extends Animal { |
那么现在Java3y想要一只狗,跟了宠物店老板说,宠物店老板就去找狗回来了:
1 | // 去找狗工厂拿一只狗过来 |
那么现在Java3y想要一只猫,跟了宠物店老板说,宠物店老板就去找猫回来了:
1 | // 去找猫工厂拿一只猫过来 |
如果这个时候Java3y说想要一只蜥蜴怎么办啊?没问题啊,店主搞个蜥蜴工厂就好了~~
1 | // 要买蜥蜴.. |
优点:
- 1:客户端不需要在负责对象的创建,明确了各个类的职责
- 2:如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可
- 3:不会影响已有的代码,后期维护容易,增强系统的扩展性
缺点:
- 1:需要额外的编写代码,增加了工作量
工厂方法类图:
简单/静态工厂模式
现在宠物店生意不好做啊,号称“什么宠物都有”,这吹过头了~~于是店主只卖两种常见的宠物了。
- 既然就只有两种宠物的话,那就没必要有”猫厂“、”狗厂“了,一个猫狗厂就行了!
所以我们的工厂是这样子的:
1 | public class AnimalFactory { |
三个实体还是没变(动物、猫、狗)….
那么Java3y去宠物店买猫狗的时候,告诉老板我要猫、我要狗:
1 | // 拿到狗 |
现在问题来了:
- 1:我想要一个猪,可是我的工厂类没有猪
- 2:我就去改代码,写可以创建猪对象的
- 3:接着,我又要其他的动物
- 4:我还是得改代码
- 5……………….
- 6:这就是简单工厂类的缺点:当需求改变了,我就要改代码.
简单工厂类的优点也很明显:我就一个具体的工厂来创建对象,代码量少。
抽象工厂模式
抽象工厂模式就比较复杂了,我们一般的应用都写不到。我首先来简述一下需求吧:
- 现在非常流行在猫狗届也吹起了一股“性别风”
- 有的喜欢公的
- 有的喜欢母的
那我们的猫和狗都是有性别的,不是公的就是母的~~
- 我们之前在工厂方法模式下是每个动物都开一个工厂,如果动物过多的话,那么就有很多的工厂~
- 那现在我们可以抽取出来:每个动物不是公的就是母的~
- 所以我们有两个工厂就足够了!
具体的代码是这样的:
我们的最大工厂还是定义了创建什么动物
1 | public interface AnimalFactory { |
创建母猫和母狗的工厂:
1 | public class FemaleAnimalFactory implements AnimalFactory { |
创建公猫和公狗的工厂:
1 | public class MaleAnimalFactory implements AnimalFactory { |
这是所有动物都拥有的普遍行为:
1 | public abstract class Animal { |
这是猫都拥有的普遍行为:
1 | public abstract class Cat extends Animal { |
这是狗都拥有的普遍行为:
1 | public abstract class Dog extends Animal { |
猫分为公猫、母猫。狗分为公狗和母狗:
1 | public class FemaleCat extends Cat { |
…..
简单来说:工厂方法模式的工厂是创建出一种产品,而抽象工厂是创建出一类产品。
- 一类的产品我们称之为产品族
- 猫是一类的,狗也是一类的。所以AnimalFactory定义了两类产品—>
Animal createDog();
和Animal createCat();
- 猫是一类的,狗也是一类的。所以AnimalFactory定义了两类产品—>
- 产品的继承结构称之为产品等级
- 所有的动物都是会吃东西的,它们都是有性别的,这是最普遍的。所以Animal定义了两个抽象方法:
public abstract void eat();
和public abstract void gender();
- 所有的狗都是会吃肉的,所以Dog实现了eat()方法
- 狗又分成了公狗和母狗,所以定义了两个类FemaleDog和MaleDog继承了Dog,实现了
gender()
方法
- 狗又分成了公狗和母狗,所以定义了两个类FemaleDog和MaleDog继承了Dog,实现了
- 所有的猫都是会吃鱼的,所以Cat实现了eat()方法
- 猫又分成了公猫和母猫,所以定义了两个类FemaleCat和MaleCat继承了Cat,实现了
gender()
方法
- 猫又分成了公猫和母猫,所以定义了两个类FemaleCat和MaleCat继承了Cat,实现了
- 所有的动物都是会吃东西的,它们都是有性别的,这是最普遍的。所以Animal定义了两个抽象方法:
- 具体的工厂是面向多个产品等级结构进行生产。
- 所以FemaleAnimalFactory定义了
createDog()
和createCat()
生产母狗和母猫 - 所以MaleAnimalFactory定义了
createDog()
和createCat()
生产公狗和共猫
- 所以FemaleAnimalFactory定义了
- 找到母工厂就可以创建母猫和母狗,找到公工厂就可以创建公猫和公狗
抽象工厂模式说到底就是多了一层抽象,减少了工厂的数量。
抽象工厂缺点也很明显:
- 难以扩展产品族—>如果我再要宠物猪的话
- 那我要修改AnimalFactory、FemaleAnimalFactory、MaleAnimalFactory这些类了~
总结
总的来说我们用简单工厂模式比较多,工厂方式模式的话代码量会比较大,抽象工厂模式的话需要业务比较大的情况下才会用到
- 工厂模式将初始化一个类所需要的繁杂操作,包装在了一个工厂的方法当中。如考虑声明一个缓冲区,缓冲区有不同的类型,封装在不同的工厂方法当中
- 工厂模式配合反射来使用也是极好的~