当前位置:网站首页>Do you understand the factory pattern?
Do you understand the factory pattern?
2022-08-03 00:09:00 【horse crumbs】
Factory pattern iPersonally, I think it's more difficult to understand,如果有接触过|听过|见过该模式的同学很可能就会想:我自己new
一个对象出来就好了,简单快捷.用得着你这个工厂模式吗?搞一个工厂出来还要写一大堆的代码呢~
网上的很多资料都是在阐述着:The advantage of the factory pattern is that解耦.相信大家对解耦This word is also not unfamiliar,那解耦究竟有什么好处呢?
本文章试图去解释为什么要用工厂模式,用了工厂模式的好处是什么,以及工厂模式衍生出的三种形式究竟有什么区别~~
那么接下来就开始吧,如果有错的地方希望能多多包涵,并不吝在评论区指正!
一、工厂模式概述
在《设计模式之禅》这本书中分了两章节讲工厂模式:
工厂方法模式
(ps:其中里面讲到了简单工厂模式)
抽象工厂模式
Most of the information on the Internet divides the factory model into三种:
简单/静态工厂模式
工厂方法模式
抽象工厂模式
看完上面的叙述是不是想打死我,什么鸟玩意?不急哈,下面我会一一讲到~~
1.1为什么要用工厂模式?
想想我们为什么要用工厂模式?下面我就简单举例子:
文件IO的操作我们会经常用得到吧,所以BufferedReader对象经常要创建的:
// 创建一个BufferedReader对象
BufferedReader bf = new BufferedReader(new FileReader(new File("aa.txt")));
你说麻烦吗?其实也不麻烦,就一行代码嘛,哪里麻烦了~如果不太熟悉IO流的同学就没有那么机灵了,创建一个BufferedReader可能就是以下的代码了:
File file = new File("aa.txt");
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);
你说麻烦吗?其实也不麻烦,不就是三行代码嘛,哪里麻烦了~如果这个应用很多的类上都用到了BufferedReader对象的话,那每个类都写上这三行代码了.那你说麻烦吗?那肯定麻烦啊,还用想啊….
可以看出来,创建一个BufferReader对象里面需要一个FileReader对象,而FileReader对象又要File对象.那创建这个BufferReader对象还是比较麻烦的(代码上看不麻烦,从构造上看还是挺麻烦的)!
虽然比较麻烦,但我们还能用,能用就行!于是乎,我们就去写代码了,现在有三个类都要进行文件的读写操作,于是他们就有这样的代码:
public class FileOperateA {
public static void main(String[] args) throws FileNotFoundException {
File file = new File("aa.txt");
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);
// 读写文件....
}
}
此时:上头说,我要换成LineNumberReader来读写,有这个需求!那我们作为一个写代码的,能怎么办?很绝望也需要去完成呀.
不熟悉IDE的小伙子就一个一个将BufferedReader改成LineNumberReader,现在就3个类用到了BufferedReader,也就改6次而已.(ps:那如果很多地方都用到了呢?)
熟悉IDE的小伙子就全局替换重构,妥妥的!
哎,写个代码屁事真多…Is there a way to do thatCreating objects made easy而且Can be very convenient when modifying objects呢?
哎,工厂模式就行了.
再说从Object-oriented point of view:我一个操作文件的类还要我会创建BufferReader是不是有点过分了?(职责没有分工好)
交给工厂来创建对象这就很面向对象了!
1.2体验工厂模式
何为工厂?将我们的产品都交由工厂来生产!我现在用的iphone5s,从哪来?从富士康组装而来,富士康是工厂.我用得着知道iphone5s在富士康是怎么组装起来的吗?不需要.
来,我们来改造一下上面的例子.首先我们创建一个工厂类,它可以生产Reader对象!
// 创建Reader对象的工厂
public class ReaderFactory {
public static Reader getReader() throws FileNotFoundException {
File file = new File("aa.txt");
FileReader fileReader = new FileReader(file);
BufferedReader reader = new BufferedReader(fileReader);
return reader;
}
}
那么我们要得到BufferReader对象就贼简单了:
public class FileOperateA {
public static void main(String[] args) throws FileNotFoundException {
//-------我有工厂了,还用自己搞吗?不用了!
//File file = new File("aa.txt");
//FileReader fileReader = new FileReader(file);
//BufferedReader bufferedReader = new BufferedReader(fileReader);
//-------我有工厂了,还用自己搞吗?不用了!
// 用工厂来创建出对象
Reader reader = ReaderFactory.getReader();
// 读写文件....
}
}
The factory will usThe object process created is blocked!
此时我要改成LineNumberReader怎么玩?在Change it at the factory就好了:
我们的调用方FileOperateA|FileOperateB|FileOperateC
这些类完全就不用变!
1.3使用工厂方法的好处
从上面的工厂模式体验我们就可以看到:
我们修改了具体的实现类,对客户端(调用方)而言是No modification at all.
如果我们使用
new
的方式来创建对象的话,那么我们就说:new
出来的这个对象和当前客户端(调用方)耦合了!也就是,当前客户端(调用方)依赖着这个
new
出来的对象!
这就是解耦的好处!
我再放下我之前练习的时候写过的代码吧:
我有一个DaoFactory,The logic is simple专门创建Dao对象的~
那么在Service层就可以Using a factory would be what you wantDao对象初始化了~
此时我们的Service与Dao的对象低耦合的~
大家Might not see any benefit,还弄了一大堆的字符串啥的~~
在Service与Controller层我也弄了一个ServiceFactory,根据当时业务的需要(添加权限),我创建Servicevery flexible了:
二、如何使用工厂模式
在一开始我就说了,工厂模式可以分成三类:
简单/静态工厂模式
工厂方法模式
抽象工厂模式
下面我就逐一来介绍一下每一种工厂模式有什么不一样~
三种模式都以:Java3y要买宠物的例子来讲解~
2.1工厂方法模式
很多博客都是以简单/静态工厂模式,工厂方法模式,抽象工厂模式这个顺序来讲解工厂模式的.我认为按书上的顺序比较好理解~因为简单/The static factory pattern is on the factory method pattern缩减,The abstract factory pattern is based on the factory method pattern增强.
所以我就先讲工厂方法模式了.
Java3y每天写代码很无聊,想要买只宠物来陪陪自己.So it isGo to the pet store to see pets~~~
作为一间宠物店,号称什么宠物都有!于是乎,店主宣传的时候就说:my pet store什么宠物都有!
于是构建宠物的工厂就诞生了~
// 号称什么宠物都有
public interface AnimalFactory {
// 可以获取任何的宠物
Animal createAnimal();
}
当然了,主流的宠物得进货一些先放在店里充充门面,一些特殊的宠物就告诉顾客要时间进货~
所以,我们就有了构建猫和狗的工厂(继承着所有宠物的工厂)
猫工厂:
// 继承着宠物工厂
public class CatFactory implements AnimalFactory {
@Override
// 创建猫
public Animal createAnimal() {
return new Cat();
}
}
狗工厂也是一样的:
// 继承着宠物工厂
public class DogFactory implements AnimalFactory {
// 创建狗
@Override
public Animal createAnimal() {
return new Dog();
}
}
嗯,还有我们的实体类:猫、狗、动物(多态:猫和狗都是动物,可以直接用动物来表示了)
动物实体类:
public abstract class Animal {
// 所有的动物都会吃东西
public abstract void eat();
}
猫实体类:
public class Cat extends Animal {
// 猫喜欢吃鱼
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
狗实体类:
public class Dog extends Animal {
// 狗喜欢吃肉
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
那么现在Java3y想要一只狗,跟了宠物店老板说,宠物店老板就去找狗回来了:
// 去找狗工厂拿一只狗过来
AnimalFactory f = new DogFactory();
// 店主就拿到了一只狗给Java3y
Animal a = f.createAnimal();
a.eat();
System.out.println("Java3y");
那么现在Java3y想要一只猫,跟了宠物店老板说,宠物店老板就去找猫回来了:
// 去找猫工厂拿一只猫过来
AnimalFactory ff = new CatFactory();
// 店主就拿到了一只猫给Java3y
Animal aa = ff.createAnimal();
aa.eat();
System.out.println("Java3y");
如果这个时候Java3y说想要一只蜥蜴怎么办啊?没问题啊,店主Start a lizard factory就好了~~
// 要买蜥蜴..
AnimalFactory fff = new LizardFactory();
Animal aaa = ff.createAnimal();
aaa.eat();
优点:
1:客户端不需要在负责对象的创建,明确了各个类的职责
2:如果有New objects are added,只需要Add a concrete class and concrete factory class即可
3:不会影响已有的代码,后期维护容易,增强系统的扩展性
缺点:
1:需要额外的编写代码,增加了工作量
工厂方法类图:
2.2简单/静态工厂模式
现在宠物店生意不好做啊,号称“什么宠物都有",这吹过头了~~So the ownerOnly two common pets are sold了.
既然就只有两种宠物的话,那就没必要有”猫厂“、”狗厂“了,一个猫狗厂就行了!
所以我们的工厂是这样子的:
public class AnimalFactory {
public static Dog createDog() {
return new Dog();
}
public static Cat createCat() {
return new Cat();
}
// 外界想要猫要狗,这里创建就好了
public static Animal createAnimal(String type) {
if ("dog".equals(type)) {
return new Dog();
} else if ("cat".equals(type)) {
return new Cat();
} else {
return null;
}
}
}
三个实体还是没变(动物、猫、狗)….
那么Java3y去宠物店买猫狗的时候,告诉老板我要猫、我要狗:
// 拿到狗
Animal A = AnimalFactory.createAnimal("dog");
A.eat();
// 拿到猫
Animal C = AnimalFactory.createAnimal("cat");
C.eat();
现在问题来了:
1:我想要一个猪,可是我的工厂类没有猪
2:我就去改代码,写可以创建猪对象的
3:接着,我又要其他的动物
4:I still have to改代码
5……………….
6:这就是简单工厂类的缺点:当需求改变了,我就要改代码.
简单工厂类的优点也很明显:我Just a concrete factory to create objects,代码量少.
2.3抽象工厂模式
抽象工厂模式就比较复杂了,我们General applications cannot be written.我首先来简述一下需求吧:
现在非常流行在猫狗届也吹起了一股“性别风”
有的喜欢公的
有的喜欢母的
那我们的猫和狗都是有性别的,不是公的就是母的~~
我们之前在工厂方法模式下是每个动物都开一个工厂,如果动物过多的话,那么就有很多的工厂~
Well now we can抽取出来:每个动物不是公的就是母的~
所以我们有两个工厂就足够了!
具体的代码是这样的:
我们的最大工厂还是定义了创建什么动物
public interface AnimalFactory {
Animal createDog();
Animal createCat();
}
创建母猫和母狗的工厂:
public class FemaleAnimalFactory implements AnimalFactory {
// 生产母狗和母猫
@Override
public Animal createDog() {
return new FemaleDog();
}
@Override
public Animal createCat() {
return new FemaleCat();
}
}
创建公猫和公狗的工厂:
public class MaleAnimalFactory implements AnimalFactory {
// 生产公狗和公猫
@Override
public Animal createDog() {
return new MaleDog();
}
@Override
public Animal createCat() {
return new MaleCat();
}
}
这是A common behavior that all animals possess:
public abstract class Animal {
// 所有的动物都会吃东西
public abstract void eat();
// 所有的动物都有性别
public abstract void gender();
}
这是猫都拥有的普遍行为:
public abstract class Cat extends Animal {
// 猫喜欢吃鱼
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
这是狗都拥有的普遍行为:
public abstract class Dog extends Animal {
// 狗喜欢吃肉
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
猫分为公猫、母猫.狗分为公狗和母狗:
public class FemaleCat extends Cat {
public void gender() {
System.out.println("I am a female Cat");
}
}
…..
简单来说:The factory method pattern of factories is created out一种产品,And the abstract factory is created一类产品.
所有的狗都是会吃肉的,所以Dog实现了
eat()
方法狗又分成了公狗和母狗,所以定义了两个类FemaleDog和MaleDog继承了Dog,实现了
gender()
方法
所有的猫都是会吃鱼的,所以Cat实现了
eat()
方法猫又分成了公猫和母猫,所以定义了两个类FemaleCat和MaleCat继承了Cat,实现了
gender()
方法
A class of products we call it产品族.
猫是一类的,狗也是一类的.所以AnimalFactory定义了两类产品--->
Animal createDog();
和Animal createCat();
产品的继承结构称之为产品等级.
具体的工厂是Manufacture for multiple product hierarchy structures.
所以FemaleAnimalFactory定义了
createDog()
和createCat()
生产母狗和母猫所以MaleAnimalFactory定义了
createDog()
和createCat()
生产公狗和共猫
找到母工厂就可以创建母猫和母狗,找到公工厂就可以创建公猫和公狗
public static void main(String[] args) {
// 需要性别为母的就去找母工厂
AnimalFactory af = new FemaleAnimalFactory();
// 需要一只母猫
af.createCat().gender();
// 需要一只母狗
af.createDog().gender();
System.out.println("-------------Java3y-------------------------");
// 需要性别为公的就去找公工厂
AnimalFactory aff = new MaleAnimalFactory();
// 需要一只公狗
aff.createDog().gender();
// 需要一只公猫
aff.createCat().gender();
}
效果:
这是抽象工厂模式的类图:
The abstract factory pattern is exactly what it is多了一层抽象,减少了工厂的数量.
抽象工厂缺点也很明显:
难以扩展产品族--->如果我再要宠物猪的话
那我要修改AnimalFactory、FemaleAnimalFactory、MaleAnimalFactory这些类了~
三、总结
总的来说我们Use the simple factory pattern more,工厂方式模式的话代码量会比较大,抽象工厂模式的话需要业务比较大的情况下才会用到(如果有更好的理解方式不妨在评论区留言,一起交流交流涨涨见识~~)
工厂模式配合反射来使用也是极好的~
边栏推荐
猜你喜欢
php 单引号 双引号 -> => return echo
Use the TCP protocol, we won't lost package?
.NET performance optimization - you should set initial size for collection types
The software testing process specification is what?Specific what to do?
手把手教你干掉if else
UDP(用户数据报协议)
【3D视觉】realsense D435三维重建
VisualStudio 制作Dynamic Link Library动态链接库文件
华为设备配置BFD多跳检测
sre成长之路
随机推荐
引用类型 ,值类型 ,小坑。
golang刷letcode:公司命名
[21 Days Learning Challenge] Bubble Sort and Insertion Sort
封装和包、访问修饰权限
MSTP与STP
Wiring diagrams of switches, motors, circuit breakers, thermocouples, and meters
The software testing process specification is what?Specific what to do?
最近火爆朋友圈的“广告电商”,核心商业模式是什么,广告收入真实靠谱吗?
快速构建电脑软件系统 、超好用经典的网页推荐汇总
Which thread pool does Async use?
单例模式你会几种写法?
如何成为一名正义黑客?你应该学习什么?
golang 刷leetcode:Morris 遍历
@Transactional 事务调用与生效场景总结
golang 刷leetcode:将字符串翻转到单调递增
Details in C# you don't know
增删改查这么多年,最后栽在MySQL的架构设计上!
正则表达式
汇编语言中b和bl关键字的区别
callback prototype __proto__