上一次我们已经通过代码,简单的认识了工厂方法模式,具体的思路请移步到设计模式之工厂模式(二),进行查看。这次,让我们通过设计模式的思想,来好好认识下工厂方法模式。

创建者和产品

所有工厂模式都用来封装对象的创建。工厂方法模式(Factory Method Pattern)通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。让我们来看看这些类图,以了解有哪些组成元素:

另一个观点:平行的类层级

上面已经看到,将一个orderPizza()方法和一个工厂方法联合起来,就可以成为一个框架。除此之外,工厂方法将生产知识封装进各个创建者,这样的做法,也可以被视为是一个框架。

让我们来看看这两个平行的类层级,并认清它们的关系:

定义工厂方法模式

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

工厂方法模式能够封装具体类型的实例化。看下面的类图,抽象的Creator提供了一个创建对象的方法的接口,也称为“工厂方法”。在抽象的Creator中,任何其他实现的方法,都可能使用到这个工厂方法所制造出来的产品,但只有子类真正实现这个工厂方法并创建产品。

对象依赖

假设你从未听过工厂模式,那么按照之前的,如果要开一家纽约和芝加哥的披萨店,并且有各种风味的披萨对象,你是否可以想象这个类所以来的具体披萨对象有几种呢?如果又增加了一种加州风味,又会有依赖多少个对象呢?不妨让你看看:

public lass DependentPizzaStore {public Pizza createPizza(String style, String type) {Pizza pizza = null;if(style.equals("NY")) {if(type.equals("cheese")) {pizza = new NYStyleCheesePizza();} else if(tpye.equals("clam")) {pizza = new NYStyleClamPizza();} else if(type.equals("pepperoni")) {pizza = new NYStylePrpperoniPizza();}} else if(style.equals("Chicago")) {if(type.equals("cheese")) {pizza = new ChicagoStyleCheesePizza();} else if(tpye.equals("clam")) {pizza = new ChicagoStyleClamPizza();} else if(type.equals("pepperoni")) {pizza = new ChicagoStylePrpperoniPizza();}} else {System.out.println("Error: invalid type of pizza");return null;}}
}
复制代码

当你直接实例化一个对象时,就是在依赖它的具体类。如果把这个版本的披萨店和它的依赖对象画成一张画,看起来是这样的:

依赖倒置原则

从上面看到了,我们代码里减少对于具体类的依赖是一件好事。事实上,有一个OO设计原则就正式阐明了这一点;这个原则甚至还有一个又响亮又正式的名称:“依赖倒置原则”要依赖抽象,不要依赖具体类

这个原则和“针对接口编程,不针对实现编程”类似,但是这个原则,更强调“抽象”。这个原则说明了:不能让高层组件依赖低层组件,而且,不管高层或低层组件,“两者”都应该依赖于抽象。

所谓“高层”组件, 是是由其他低层组件定义行为的类。例如,PizzaStore是个高层组件,因为他的行为是由披萨定义的;PizzaStore创建所有不同的披萨对象,准备、烘烤、切片、装盒;而披萨本身属于低层组件。PizzaStore依赖这些具体披萨类。

原则的应用

非常依赖披萨店的主要问题在于:它依赖每个披萨类型。因为它是在自己的orderPizza()方法中,实例化这些具体类型的。

如何在orderPizza()方法中,将这些实例化对象的代码独立出来?我们都知道,工厂方法刚好派上用场了。应用了工厂方法之后,类图就改成了下面这个样子:

在应用工厂方法之后,你注意到了没,高层组件(PizzaStore)和低层组件(也就是这些披萨)都依赖了Pizza抽象。想要遵循依赖倒置原则,工厂方法并非是唯一的技巧,但却是最有威力的技巧之一了。

依赖倒置,究竟倒置在哪里?

在依赖倒置原则中的倒置指的是和一般OO设计的思考方式相反。看看上面的图,你会注意到低层组件现在竟然依赖高层的抽象。同样地,高层组件现在也依赖相同的抽象。以前绘制的依赖图都是自上而下的,现在却倒置了,而且高层和低层模块现在都依赖这个抽象。

依赖倒置,还需要倒置你的思考方式。之前如果你需要设计一个披萨店,会从顶端开始,然后往下到具体类。现在就需要倒置你的想法,别从顶端开始,而是从披萨开始,然后想到抽象化一个Pizza类。继而想到必须要靠一个工厂来将这些类取出披萨店,不同的披萨类型都只能依赖一个抽象,同样的披萨店也会依赖这个抽象。

就这样,我们倒置了一个商店依赖具体类的设计,而且也倒置了你的思考方式。但是,也需要避免在OO设计中违反依赖倒置原则:

  1. 变量不可以持有具体类的引用:如果使用new,就会持有具体类的引用。你可以改用工厂来避开这样的做法
  2. 不要让类派生自具体类:如果派生自具体类,你就会依赖具体类。请派生自一个抽象(接口或抽象类)
  3. 不要覆盖基类中已实现的方法:如果覆盖基类已实现的方法,那么你的基类就不是一个真正适合被继承的抽象。基类中已实现的方法,应该由所有的子类共享

所以,这篇我们就在这里结束了。为什么呢,因为在下一篇,我们需要遵循这个设计原则,重新来整理整理我们的披萨店。我们要让披萨店的设计变得更棒:具有弹性的框架,而且遵循设计原则。这篇偏向理论知识了,请各位好好理解理解,看看创建者和产品类,看看依赖倒置原则,我们下篇再见咯。

爱生活,爱学习,爱感悟,爱挨踢

转载于:https://juejin.im/post/5cbd42956fb9a032060c2615

设计模式之工厂模式(三)相关推荐

  1. JavaScript设计模式--简单工厂模式例子---XHR工厂

    JavaScript设计模式--简单工厂模式例子---XHR工厂 第一步,Ajax操作接口(目的是起一个接口检测作用) (1)引入接口文件 //定义一个静态方法来实现接口与实现类的直接检验 //静态方 ...

  2. 三角形圆形创建与擦除java_设计模式---------------简单工厂模式

    设计模式---------------简单工厂模式 一.题目(Question) 使用简单工厂模式设计一个可以创建不同几何形状(如圆形.方形和三角形等)的绘图工具,每个几何图形都要有绘制draw()和 ...

  3. Java 设计模式之工厂模式(二)

    原文地址:Java 设计模式之工厂模式(二) 博客地址:http://www.extlight.com 一.背景 本篇内容是 Java 设计模式创建型模式的第二篇.上一篇主题为 <Java 设计 ...

  4. php工厂模式和单例模式,php 设计模式之工厂模式、单例模式、注册树模式

    php 设计模式之工厂模式.单例模式.注册树模式 在软件工程中,创建型设计模式承担着对象创建的职责,尝试创建适合程序上下文的对象,对象创建设计模式的产生是由于软件工程设计的问题,具体说是向设计中增加复 ...

  5. 教你如何一篇博客读懂设计模式之—--工厂模式

    一篇博客读懂设计模式之-工厂模式 工厂模式在我们日常开发的时候经常用到,相信大家都有了一定的了解,工厂模式是一种创建对象的设计模式,它提供一种创建对象的最佳方式. 主要过程是: 定义一个创建对象的接口 ...

  6. 系统架构技能之设计模式-抽象工厂模式

    一.上篇回顾 上篇我们主要讲述了简单工厂模式和工厂模式.并且分析了每种模式的应用场景和一些优缺点,我们现在来回顾一下: 简单工厂模式:一个工厂负责所有类型对象的创建,不支持无缝的新增新的类型对象的创建 ...

  7. java设计模式之工厂模式(UML类图分析+代码详解)

    大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!! 本文将介绍java设 ...

  8. java 设计模式 路由器_java设计模式2————工厂模式

    java设计模式2----工厂模式 1.工厂模式介绍: 1.1.实现了创建者与调用者的分离 1.2.详细分类: 简单工厂模式 工厂方法模式 抽象工厂模式 1.3.所遵循的OOP原则: 开闭原则:对扩展 ...

  9. 设计模式之工厂模式(Factory)

    设计模式之工厂模式 设计模式之工厂模式 简介 代码准备 需求一 需求二 简单工厂 工厂方法 抽象工厂 需求三 总结 设计模式之工厂模式 简介 工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可 ...

最新文章

  1. vue渲染大量数据如何优化_Vue3 Compiler 优化细节,如何手写高性能渲染函数
  2. C语言-数组名真的不是指针
  3. centos7已有数据硬盘挂载_实战2T以上盘GPT分区工具使用挂载教程
  4. POJ 2342 (树形DP)
  5. 多种时间格式字符串转换为Date对象
  6. IDirect3DDevice9::SetClipPlane
  7. ubuntu 安装 最新 PyMOL [源码安装][免费]
  8. linux gns3使用教程,Linux下GNS3报错解决方法
  9. 整个社会总嫌自己不够“快”,为啥?
  10. Intellij如何把JAR包加入到项目运行环境中
  11. 鸿蒙os 实测,鸿蒙体验怎么样_鸿蒙OS实测体验
  12. 自定义Xshell高亮
  13. Apache Http Server安全漏洞解决
  14. dcos 1.7 安装
  15. pyhton 将ASCII码转换为字符char(),将字符转换为ASCII码ord()
  16. 从技术 Leader 的招聘需求看,如何转岗为当前紧缺的大数据相关人才?
  17. android 自定义音量调节,Android——自定义音量调节控件
  18. 微信企业号开发—通讯录
  19. H323加载H264插件时出现找不到dll文件问题解决
  20. 详解Unity中的粒子系统Particle System (六)

热门文章

  1. python字符编码
  2. React Native移动开发实战-4-Android平台的适配
  3. 《写给大家看的设计书:实例与创意(修订版)》—1你已经知道多少了?
  4. 【博客美化】08.添加扩大/缩小浏览区域大小 按钮
  5. MYSQL的索引类型:PRIMARY, INDEX,UNIQUE,FULLTEXT,SPAIAL 有什么区别?各适用于什么场合?...
  6. 【百度地图API】暑假放假回老家——城市切换功能
  7. ubuntu 12.10 php55安装过程
  8. Ubuntu 10.04 lucid 安装 MariaDB 5.5
  9. 迷你图标集大集合:5000+ 30套免费的图标
  10. 微软将迎来迄今最大补丁日 一次修补49个漏洞