文章已收录我的仓库:Java学习笔记与免费书籍分享

模式类型

工厂模式属于创建者模式,与对象的创建有关,其中工厂方法模式用于类,而抽象工厂模式用于对象。创建型类模式将对象的部分创建工作延迟到子类,由子类创建对象;而创建型对象模式将它延迟到另一个对象中。

模式设计意图

工厂模式将复杂的对象创建工作隐藏起来,而仅仅暴露出一个接口供客户使用,具体的创建工作由工厂管理而对用户封装,将对象的创建和使用分离开来,降低耦合度,便于管理,能够很好的支持变化。

对于某些类而言,其对象的创建可能是需要一系列复杂的参数或大量准备代码,当这个任务由客户完成时,如果客户创建多个复杂对象,先不说这些代码可能难以编写,也会造成不必要的代码重复,交给工厂产生对象则不会造成代码重复,因为工厂中的代码写一次便可以复用无数次,能够减少代码量,并且用户无需关注这些难以编写的代码,增加可读性,例如Spring框架中的beanFactory便是如此。

此外,将对象的创建和使用分离开来,所有的创建工作由工厂管理,工厂可以管理类并适应相应业务变化,而无须对客户暴露,例如如果某个产品A升级为AA,我们可以直接在工厂中将return new A()改为return new AA(),客户仍然调用factory.createProductA()而无须变更代码,如果客户是通过new A()的形式创建对象,那么我们还需要找到所有的代码并把它们改成new AA(),这在一个庞大的工程中是一项巨大的任务。

当客户使用的对象可能发生变化时,例如一开始使用A产品而后来想使用B产品时,普通的方式我们可能不得不更改所有的new方法,如果使用简单工厂模式,可以仅仅更改配置文件而无须更改客户代码来完成这个目的,如果使用工厂方法模式或者抽象工厂模式,那么可以调整工厂的构造函数或者使用set注入来达到这个目的,大大减少因变化而造成的不适应性。

上述所说的一切都归功于将类的使用与创建解耦,这也就是整个工厂模式的核心思想与设计意图。无论何时,高内聚、低耦合永远都是编写需要考虑到的地方。

工厂模式具体分为简单工厂、工厂方法和抽象工厂模式,这些方法都符合上述设计意图,但同时又满足不同的需求、适应不同的场景。

简单工厂(Simple Factory)

设计

定义一个创建对象的接口,创建一个子类通过传入的参数决定创建哪一种实例。

适用场景

  • 工厂类负责生产的对象较少。
  • 一个类不确定它所必须创建的对象的类的时候,具备不确定性。
  • 客户知道需要传入工厂的参数而并不关心具体的类创建逻辑。

代码实例

假设我们具有如下需求:一家游戏厂商开发了A、B、C三种游戏,某个测试者被要求试玩相应游戏。

//定义游戏接口
interface Game {public void play();
}//A游戏
class GameA implements Game{public void play(){System.out.println("Playing GameA");};
}//B游戏
class GameB implements Game{public void play(){System.out.println("Playing GameB");};
}//C游戏
class GameC implements Game{public void play(){System.out.println("Playing GameC");};
}class GameFactory {public Game createGame(char type) {switch (type) {case 'A':return new GameA();case 'B':return new GameB();case 'C':return new GameC();}return null;}
}//测试者(客户)类
class Tester {private char type;public Tester(char type) {this.type = type;}public void testGame() {GameFactory gameFactory = new GameFactory();//通过简单工厂获取游戏实例Game game = gameFactory.createGame(type);//试玩游戏game.play();}}//代码测试
public class Test {public static void main(String[] args) {//要求测试者试玩游戏ATester tester = new Tester('A');tester.testGame();}
}

在测试代码Test类中我们是这样写的:

Tester tester = new Tester('A');

事实上在工程中我们并不直接写类型,而是导入配置文件:

Tester tester = new Tester(config.GAME_TYPE);

这样如果我们想要让测试者测试不同的游戏时,就可以修改config配置文件中的GAME_TYPE(它可以是数组)信息(还可以利用反射),这就使得代码能够适应变化。

如果每个类的构造准备工作都是一致的初始化(上述代码没有任何准备工作而直接返回),可以考虑采用哈希表存储参数与实例之间的关系,可以减少大量if-else语句。在这种情况下我们需要提前在哈希表中初始化并存储相关实例而没有考虑程序是否会用上,也许会造成不必要的资源浪费,但另一方面,我们每次获取实例都是返回HashMap中实例的克隆,这样比new操作效率更高——这其实就是享元设计模式。不过,大多数情况下我们仍需要对不同的实例进行不同的初始化操作,此时仍需要大量的判断语句。(如果类真的具有一致性而采用Map缓存,事实上这种设计模式就是策略模式,策略模式是编程中最基本的设计模式,我们大多都在有意无意的使用——定义算法接口并由子类实现不同算法,定义相关类以选择这些子类。)

UML类图

总结

简单工厂模式的结构非常简单,易于使用,当对象实例较少时可以考虑简单工厂模式。通过UML类图可以发现,简单工厂模式对客户封装了具体创建类的逻辑过程,所以我们可以在工厂中进行一些复杂的初始化或其他操作帮助客户减轻压力,用户仅仅需要知道传入的具体参数即可获得相应实例。简单工厂模式也可以应对适量的业务变化而不影响客户代码,符合工厂模式的设计意图。

简单工厂模式的缺点也是很明显的,正如它的名字,它仅仅适用于较为简单的场景,而对稍加复杂的情况会使得简单工厂无比庞大而难以维护,当增加或减少实例时,我们必须对工厂进行较为大量的修改,这违反了开闭原则。此外,当工厂出现BUG时,整个程序将会崩溃。

工厂方法(Factory Method)

设计

定义一个创建对象的接口,由子类决定实例化哪一个类,工厂方法将类的实例化推迟到子类实现。

适用场景

  • 一个类不确定它所必须创建的对象的类的时候,具备不确定性。
  • 你期望获得较高的扩展性。
  • 当一个类希望由它的子类来指定它所创建的对象。
  • 当类将创建对象的职责委托给多个帮忙子类的中的某一个,并且客户知道将要使用哪一个帮忙子类。

代码实例

假设我们同样具有需求:一家游戏厂商开发了A、B、C三种游戏,测试者被要求试玩相应游戏。

//定义游戏接口
interface Game {public void play();
}//A游戏
class GameA implements Game{public void play(){System.out.println("Playing GameA");};
}//B游戏
class GameB implements Game{public void play(){System.out.println("Playing GameB");};
}//C游戏
class GameC implements Game{public void play(){System.out.println("Playing GameC");};
}//定义工厂(父类)
interface GameFactory {Game createGame();
}//帮忙子类,游戏A工厂
class GameAFactory implements GameFactory {@Overridepublic Game createGame() {return new GameA();}
}//帮忙子类,游戏B工厂
class GameBFactory implements GameFactory {@Overridepublic Game createGame() {return new GameB();}
}//帮忙子类,游戏C工厂
class GameCFactory implements GameFactory {@Overridepublic Game createGame() {return new GameC();}
}//测试者(客户)类
class Tester {private GameFactory gameFactory;public Tester(GameFactory gameFactory) {this.gameFactory = gameFactory;}public void testGame() {//通过工厂获取游戏实例Game game = gameFactory.createGame();//试玩游戏game.play();}}//代码测试
public class Test {public static void main(String[] args) {//要求测试者1试玩游戏AGameFactory gameFactory = new GameAFactory();Tester tester1 = new Tester(gameFactory);tester1.testGame();//要求测试者2也试玩游戏ATester tester2 = new Tester(gameFactory);tester2.testGame();//... 测试者1000也试玩游戏A}
}

我们可以通过更改构造函数或使用set方法来更改工厂,可以更改较少的代码就能让所有测试者都更改试玩游戏(最坏情况下仍然需要更改较多代码),具有较好的灵活性。

UML类图

总结

工厂方法模式其实就是简单工厂模式一种扩展,工厂方法模式具有高扩展性,如果后续想要增加类时,直接编写一个新的帮忙子类即可,可以很方便的生产或切换产品,而无需修改现有的代码,完美符合了开闭原则·。

工厂方法模式是工程中较为理想的一种设计模式,但它的缺点也是明显的,当客户新建一个产品时,就不得不创建一个产品工厂,增加了代码量,而且对于父类接口难以进行修改,因为一旦修改接口,就必须要对众多的帮忙子类进行修改。

抽象工厂(Abstract Factory)

设计

提供一个接口以创建一系列相关或互相依赖的对象,将类的实例化延迟到子类。

适用场景

  • 代码需要与多个不同系列的相关产品交互, 但是由于无法提前获取相关信息, 或者出于对未来扩展性的考虑, 你不希望代码基于产品的具体类进行构建而仅希望显示创建它们的接口。
  • 需要创建的对象是一系列相互关联或相互依赖的产品族。
  • 当一系列中的产品被设计为一起使用时,在一个应用中仅使用同一个系列中的对象。

代码实例

假设具有需求如下:一家品牌鞋垫可以生产大号尺寸的鞋子和对应鞋垫和小号尺寸的鞋子和对应鞋垫,现在有一个客户想要购买一双鞋子穿。

//定义鞋子接口
interface Shoe {void printShone();
}//定义鞋垫接口
interface Insole {void printInsole();
}//具体产品,大号鞋子
class LargeShoes implements Shoe {@Overridepublic void printShone() {System.out.println("大号鞋子");}
}//具体产品,大号鞋垫
class LargeInsole implements Insole {@Overridepublic void printInsole() {System.out.println("大号鞋垫");}
}//具体产品,小号鞋子
class SmallShoes implements Shoe {@Overridepublic void printShone() {System.out.println("小号鞋子");}
}//具体产品,小号鞋垫
class SmallInsole implements Insole {@Overridepublic void printInsole() {System.out.println("小号鞋垫");}
}//定义完整鞋子工厂接口,一个完整的鞋子由鞋子和鞋垫组成
interface CompleteShoeFactory {Shoe createShoe();Insole createInsole();
}//大型鞋子工厂,生产配套的大号鞋子和鞋垫
class CompleteLargeShoeFactory implements CompleteShoeFactory {@Overridepublic Shoe createShoe() {return new LargeShoes();}@Overridepublic Insole createInsole() {return new LargeInsole();}
}//小号鞋子工厂,生产配套的小号鞋子和鞋垫
class CompleteSmallShoeFactory implements CompleteShoeFactory {@Overridepublic Shoe createShoe() {return new SmallShoes();}@Overridepublic Insole createInsole() {return new SmallInsole();}
}//客户类,购买鞋子
class Customer {private CompleteShoeFactory factory;public Customer(CompleteShoeFactory factory) {this.factory = factory;}//购买完整的鞋public void buyCompleteShoe() {Shoe myShoe = factory.createShoe();myShoe.printShone();Insole myInsole = factory.createInsole();myInsole.printInsole();System.out.println("我已经买了配套产品,终于有鞋穿了!");}
}//代码测试类
public class Test {public static void main(String[] args) {//购买大号鞋子//这里通常使用单例模式生成工厂CompleteShoeFactory factory = new CompleteLargeShoeFactory();Customer customer = new Customer(factory);customer.buyCompleteShoe();}
}

理解抽象工厂需要创建的对象是一系列相互关联或相互依赖的产品族的好处,例如这里的大号鞋子配大号鞋垫,小号鞋子配小号鞋垫,这就是对应的产品族,消费者要么买大号产品,要么买小号产品,不可能买大号鞋配小号鞋垫,这就使得一个具体工厂类在一个应用中仅出现一次,因此具体工厂类通常使用单例设计模式创建,由于一个具体工厂类在一个应用中仅出现一次,那么变更产品系列将十分简单,我们仅需要修改一行代码——创建工厂时的代码,这具有极大的灵活性。

UML类图

总结

抽象工厂模式用于创建的对象是一系列相互关联或相互依赖的产品族,易于交换产品系列,能够较好的应对变化。因为一个对象的产品被设计成一起工作,因此也利于维护产品的一致性,如果采用简单工厂模式,那么得创建四个工厂——大鞋子工厂、大鞋垫工厂、小鞋子工厂和鞋垫工厂,引入的类也增多,而且用户可能会不小心创建大鞋子和小鞋垫,使得结果不适配,采用抽象工厂模式则可以较好的解决这个问题。

抽象工厂模式的缺点在于当工厂接口的功能越来越多时,它会变得越来越笨重,因为所有的子类都必须要去实现这里接口,这就要保证不同系列的产品种类都是一致的,此外,后续想要增加新种类或者删减种类,都不得不对所有子类做出更改。

结语

工厂模式包括简单工厂模式,工厂方法模式,还是抽象工厂模式,它们在形式和特点上是极为相似的,而且最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。

所以,在使用工厂模式时,只需要设计的六大原则的目的是否达到了。

一文彻底弄懂工厂模式(Factory)相关推荐

  1. 一文彻底弄懂建造者模式(Builder)

    文章已收录我的仓库:Java学习笔记与免费书籍分享 设计意图 为了将复杂对象的构建与它的表示分离,使得对象可以通过不同的表示创建出来. 例如对一个迷宫可能有墙.房间和门,并且数量不计.迷宫可能仅由一堵 ...

  2. 一文彻底弄懂大端与小端

    一文彻底弄懂大端与小端 1. 端模式起源 端模式(Endian)起源于<格列佛游记>, 书中根据鸡蛋敲开的方式不同将所有人分为2类,从圆头开始敲的人被归为Big Endian,从尖头开始敲 ...

  3. 设计模式(一)工厂模式Factory(创建型)

    设计模式一 工厂模式Factory 在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的.但是在一些情况下, new操作符直接生成对象会带来一些问题. ...

  4. 设计模式(四)——工厂模式(Factory Pattern)

    工厂模式(Factory Pattern) 意义 工厂模式 实现了创建者和调用者的分离.将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦.从而提高项目的扩展和维护性 ...

  5. 设计模式 - 学习笔记 - 工厂模式Factory Pattern

    设计模式 - 学习笔记 - 工厂模式Factory Pattern 1. 简单工厂 1.1 应用场景 1.2 UML 1.3 优劣分析 好处 缺点 1.4 代码示例 抽象产品 AbstractProd ...

  6. 一个案例搞懂工厂模式和单例模式

    一个案例搞懂工厂模式和单例模式 1 单例模式 一个对象只有一个实例 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例. 注意:所有的单例模式,应当使其构造方法私有化. 1.1 ...

  7. 设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)

    工厂模式 Factory Pattern(简单工厂.工厂方法.抽象工厂) 工厂模式-创建型模式-提供了创建对象的最佳方式. 在工厂模式中,创建对象时不会对客户端暴露创建逻辑,并且是通过一个共同的接口来 ...

  8. 设计模式 ~ 创建型模式 ~ 工厂模式 ~ Factory Pattern。

    设计模式 ~ 创建型模式 ~ 工厂模式 ~ Factory Pattern. 文章目录 设计模式 ~ 创建型模式 ~ 工厂模式 ~ Factory Pattern. eg. 简单工厂模式. 结构. 优 ...

  9. 一文带你看懂工厂模式

    大家好我是mihotel,今天来总结一下设计模式中的工厂模式,在平时编程中,构建对象最常用的方式是 new 一个对象.乍一看这种做法没什么不好,而实际上这也属于一种硬编码.每 new 一个对象,相当于 ...

最新文章

  1. echarts切换折线图变大_这个月,我就和折线图杠上了...
  2. OpenGL超级宝典笔记——累积缓冲区与其他颜色操作
  3. python 3d绘图 范围_python – 在3D绘图中绘制所有三个轴上的分布轮廓
  4. MessageBoxA 和MessageBoxW
  5. java获取list redis_【快学springboot】14.操作redis之list
  6. OpenGL之gluPerspective浅析
  7. 初探SQL Server 2017 on Docker@macOS
  8. vaex 处理海量数据_核心业务“瘦身”进行时!手把手带你搭建海量数据实时处理架构...
  9. 力扣209,长度最小的子数组(滑动窗口,JavaScript)
  10. Facebook广告5大成功案例!
  11. [leetcode] 7. 整数反转
  12. C++ WinExec system 隐藏黑框;清空文件
  13. flash电脑安装包_一百余款电脑软件及安装方式,忍不住收藏起来
  14. 「需求广场」需求词更新明细(六)
  15. Chrome浏览器误删书签恢复
  16. 刚刚,百度宣布造车!
  17. Windows server 2008 R2 SP1 安装KB4512486补丁失败的解决方法
  18. 约分最简分式 (15 分)
  19. 普适计算Topic推荐-AMiner
  20. VMwarenbsp;vSpherenbsp;ESXiamp;nb…

热门文章

  1. python爬取公众号阅读量_公众号没做起来,那是你菜 | 爬取21个公众号数据后
  2. 《HelloGitHub》第 49 期
  3. java基于ssm开发的多商家书店商城系统
  4. cocos中如何让背景模糊_Cocos Creator Shader Effect 系列 - 8 - 高斯模糊
  5. Tableau 桑基图
  6. Oracle ACE,一段不可思议的旅程
  7. 时间序列平稳性检验(ADF)和白噪声检验(Ljung-Box)
  8. Java学习笔记——Number类
  9. word固定上方菜单栏
  10. 北邮智能车仿真培训(九)—— 室外光电创意组仿真