🦖
Wii
  • 原码补码反码
  • Archive
    • Job
      • Learn
      • 算法
      • Company
        • HundunDaxue
      • Company
      • 基础
        • 原码补码反码
      • 项目经验
      • require
    • Hobbies
      • Physics
        • 上帝粒子
        • 概述
        • 时间
      • Movie
        • MovieList
      • Psychology
        • Psychology
        • Chenli
          • ChenliLivingRoom
      • Philosophy
        • Philosophy
        • Conceptions
        • 导言
      • Travel
        • City
          • 昆明
          • 沈阳
        • articles-check-list
      • Sports
        • Swimming
        • Skiing
      • Earth
        • Ocean
          • Biology
      • Read
        • BookList
        • 道德经
        • BookToRead
      • Music
        • sort
      • PickUp
        • SoldiersSortie
    • Care
      • Illness
        • cold
        • 腹泻
        • acne
        • EmotionalControl
        • 咽炎
        • Anemia
      • Foods
        • 破壁机
          • 食谱
      • I
      • WishList
      • WithL
        • MF
          • LY
    • Wfw
      • QA
    • Mac
      • Brew
        • 软件安装目录
      • Usage
        • RunScriptAsRootOnBoot
        • Mac-Config
      • 制作启动U盘
      • Software
        • IntelliJIDEALicenseServer
          • run-license-server
    • PlantUML
      • plantuml
    • Windows
      • Windows常用命令
      • PowerShell
        • powershell 命令
      • Cmder
      • MTP服务驱动无法安装
    • English
      • 英语阅读2016-07-29
      • 英语阅读2016-08-11
    • Tools
      • Plantuml
        • Setup
      • Eclipse
        • Eclipse
        • Eclipse常见问题
      • CommonHotkey
      • Jetbrain
        • JetbrainIDEs
      • VSCode
      • SublimeText
        • 格式化代码
    • I
      • WHATIAM
    • Device
      • Netgear
        • Astrill
      • RPi
        • Hardware
    • AwesomeSoftware
    • RESTful
    • Course
      • 自然辩证法
        • 我国在生态文明建设中存在的困境及解决对策
        • 工程师应该具有的基本道德素养
        • 科学文化与人文文化的关系
      • 英语写作
        • Description
      • 分布式系统
        • 分布式系统概论
      • 英语口语
        • 辩论赛
    • CloudLib
      • 推荐0.1
    • Project
      • README
        • emq
          • Emq架构
        • 启动
        • Hikvision
          • TimeSetting
    • Efficient
    • Neu
      • IpCamera
        • live
        • ffmpeg
    • Matlab
      • Matlab 2016b 破解
    • SchoolWork
      • 学术道德与学术规范
    • git-push
  • Coding
    • Design Pattern
      • 设计模式笔记_四_工厂模式
      • 设计模式笔记_六_命令模式
      • 设计模式笔记_三_装饰者模式
      • 设计模式入门
      • 设计模式笔记_八_模板方法模式
      • 设计模式笔记_一_策略模式
      • 设计模式笔记_五_单件模式
      • 设计模式笔记_七_适配器模式与外观模式
      • 设计模式笔记_二_观察者模式
      • 设计模式笔记_十_状态模式
      • 设计模式笔记_九_迭代器与组合模式
    • C++
      • Notes
        • Practice
          • Logger
        • Thread
          • PosixThreadPrograming
          • ThreadNote
        • Features
          • FuturePromise
          • Lambda
        • STL
          • STLPractice
          • 迭代器
          • UnorderedMapSet
          • Containor
          • STL
          • Vector
        • CMake
          • Startup
          • CMakeExample
          • CMake
          • CMakeUsage
          • CMakeKnowledge
        • Mutex
        • Gdb
          • Gdb
        • LanguageNotes
          • Pointer
          • String
          • Functions
          • 友元
          • IO
          • OOP
          • Exceptions
          • Basic
          • 初始化
          • Random
          • 模板函数
        • Glog
          • glog
        • Thrift
          • Thrift
        • Valgrind
          • valgrind
        • 动态库 & 静态库
        • BookNotes
          • AboutC++
        • LRvalues
      • map
      • protobuf
      • Build
      • Seastar
        • Notes
          • std::move
          • Introduce
          • Install
            • BuildAndInstall
          • Steps
          • cmd
      • Tricks
      • Map
      • CommonOperation
      • FreqAlgorithm
    • Tools
      • Git
        • GitExamples
        • GitUsage
        • GitKnowledge
        • GitIgnoreExample
        • DeleteBigFileFromHistory
      • Vim
        • VimTips
        • 安装
        • Vim-Usage
        • Plugins
        • Vim-Config
      • SVN
        • svn服务器搭建
        • svn
    • Scala
      • Notes
        • Scala-模式匹配
        • Scala: 隐式
        • Scala-符号语法
        • Scala-函数
        • Scala面向对象编程
        • Scala 函数式编程
        • Scala:zipWithIndex
        • Future
        • Scala-语法
        • Scala-基础
      • DateTime
      • 规范
    • Python
      • Notes
        • BookNotes
          • 生成器
          • 垃圾回收机制
          • 数据结构
          • 数据类型
          • RegularExpression
          • 迭代器
          • NetworkProgramming
          • 函数式编程
          • 上下文管理器
          • PythonDataModel
          • 运算符
          • 魔术方法
          • 面向对象
          • 装饰器
          • 模块
          • MultithreadProgramming
          • 异常
          • 函数
        • Modules
          • stack
          • Datetime
          • shutil:文件操作
          • logging
          • urllib
          • Re
          • 容器数据类型
          • TypeError
          • str
          • queue
          • urllib-and-requests
          • Exception
          • path
          • os
        • Others
          • PythonSerialization
          • Python函数的docstring
          • PIL
          • type-cast
          • operations
          • Python-类
          • 组及命名组匹配
          • Package
          • jieba分词
          • logging模块
          • Python
          • print
        • Examples
          • 文件读取写入
          • 命名
          • 递归更改文件为windows合法名称
          • 定制命令行运行方式
          • Python处理Excel文件(xlsx文件格式)
          • 读取ini配置文件
          • tor代理
          • 添加父目录到Path
        • CommonTips
        • CodingStandards
          • python注释
          • PEP-8
      • Django
        • DjangoDocs
          • making queries
          • 设置media路径
          • models
          • manage.py使用
          • template
          • view
          • forms
          • setting.py 文件配置说明
          • nginx-deploy
          • 使用pymysql
          • 自定义tags和filters
          • admin-interface
        • DjangoRestFramework
          • Customer Permissions
          • Serializers
          • FileField绝对路径问题
          • DjangoRestFrameworkNotes
          • ViewSet
        • DjangoNotes
          • Model对象转化为Dict
          • QuerySet
      • Scrapy
        • Scrapy
        • Spider
        • Scrapy安装出错
        • Selector
        • Scrapy模拟登陆
      • Job
        • 字典
      • Pandas
        • pandas
        • PandasExamples
      • VirtualEnv
        • virtualenv
      • Numpy
        • NumpyUsage
        • numpy
      • Matplotlib
        • MatplotlibNotes
        • MatplotlibUsage
      • Database
        • 获取表字段
      • Pip
        • 更改源
      • Scipy
        • scipy
    • Web
      • 插件
        • bootstrap-table
          • bootstrap-table
        • bootstrap
          • 模态框
        • requirejs
          • requirejs
        • toastr
          • toastor
      • Koa
        • Notes
          • KoaNotes
      • SCSS
        • 常用标签
        • Watch
      • Vue
        • Notes
          • 路由
          • 参考
          • 组件
          • Plugins
          • Vuex
          • StartUp
      • 样式
      • CSS
        • CSS
      • 排版
      • Notes
        • 跨域访问
      • Hexo
        • HexoUsage
      • Nodejs
        • Koa
          • jest
          • ParamValidate
        • 仓库镜像
      • Express
        • Express
        • Jade
          • Jade
      • Canvas
        • Canvas
    • Basic
      • Data Structure
        • Heap
          • Heap
        • Tree
          • Tree
        • Benchmark
          • map
      • Boolean
      • MultithreadProgramming
      • Software Engineering
        • UML
          • UML
      • OOP
      • 介绍
    • Antlr
      • Example
      • Grammar
      • Antlr
    • Java
      • Library
        • MyBatis
          • generator
            • mybatis配置详解
          • mybatis-获取自增ID
          • mybatis
          • problems
        • log4j
          • Usage
      • Maven
        • MavenUsage
        • Maven
        • MavenProject
        • 项目RUL路径问题
        • MavenPom
        • Settings
        • PomCommon
        • PomExample
      • Notes
        • Features
          • Reflect
          • Java函数式编程
          • toMap
          • Closeable & AutoCloseable & Flushable
          • Annotations
        • Common
        • ThinkingInJava
          • 控制执行流程
          • 接口
          • 复用类
          • 内部类
          • 操作符
          • 访问权限控制
          • 一切都是对象
          • 多态
          • 初始化与清理
          • 对象导论
        • SwordToOffer
        • Network
        • Thread
          • ThreadPool
        • Basic Library
        • Collections
          • List Interface
        • CommandLine
        • Project Common
        • JavaLang
      • JVM
        • Monitor
          • Jmap
          • mat
          • Jstat
          • Monitor
        • Notes
          • JVM
        • GC
          • GC
          • Shenandoah
            • Shenandoah
        • JVM
    • Algorithm
      • Code
        • LeetCode
          • Python
            • 0000-0050
              • 0005
              • 0030
        • SwordToOffer
          • SwordToOffer
      • AlgorithmSummary
      • Classics
        • string
          • KMP
        • Other
          • FullPermutation
        • 链表
        • Sort
          • Sort
      • Other
        • README
      • Notes
        • Math
          • 两点计算直线方程
    • Go
      • Notes
        • Go Project Layout
        • Install
        • Startup
      • Basic
        • Startup
        • Types
    • JavaScript
      • MasonryLayouts
      • jquery
      • Notes
        • Promise
      • js
    • Android
      • SDK
        • 打开SDK Manager
    • C#
      • WebBrowser
      • c#图片
      • 跨线程访问控件
    • Knowledge
      • 函数式编程
      • 设计框架
    • Rules
      • Rules
    • React
      • ReactNative
        • React Native Navigation
        • 打包Apk
        • ReactNative
      • React
        • README
    • RegExp
      • 正则表达式
    • WeChatApp
      • 登陆
    • Node
      • Notes
        • StartUp
  • Computer Science
    • ICS Security
      • 工控网络
      • 工业控制系统
      • HoneyPot
        • 蜜罐软件
          • Honeyd
      • 工业以太网
      • CNVD
        • 环境及依赖
      • 现有蜜罐系统及工具
      • 工控系统安全措施
      • 蜜网
      • 蜜罐
      • 工控安全相关概念
    • Data Analysis
      • Data Mining
        • Notes
          • Data_Preprocessing
          • 数据预处理
          • 认识数据
          • Mining_Modeling
          • 数据探索
          • Python_Data_Mining_Functions
          • Python数据分析平台搭建
          • Reference_Books
          • 数据分析与挖掘基础
        • Jupyter
          • show
            • mean
      • Hadoop
        • Hadoop权威指南:数据完整性
        • Hadoop权威指南: I/O操作序 - 列化
        • Hadoop权威指南-从Hadoop URL读取数据
        • Hadoop权威指南:FSDataInputStream对象
        • HDFS常用命令
        • Hadoop权威指南:HDFS-数据流
        • Hadoop权威指南:通过distcp并行复制
        • Hadoop权威指南:压缩
        • Hadoop权威指南:HDFS-Hadoop存档
        • 解决使用Idea/Eclipse编写Hadoop程序包依赖问题
        • HDFS
        • Hadoop-命令
        • 简单javaHadoop应用程序从打包到提交运行
        • Hadoop权威指南:HDFS-写入数据
        • Hadoop权威指南:HDFS-目录,查询文件系统,删除文件
        • HadoopInputFormat-OutputFormart
        • Hadoop-HDFS命令行接口
        • Hadoop权威指南-MapReduce应用开发
        • Linux下使用javac编译Hadoop程序
        • Hadoop权威指南:通过FileSystem API读取数据
        • Hadoop专有数据类型
      • Spark
        • Spark计算模型
        • Spark-入门二
        • 安装Hadoop及Spark(Ubuntu 16.04)
        • Spark:核心概念简介
        • Spark:控制日志输入
        • Spark - RDD编程
        • Spark工作机制
        • Spark-一个独立应用
        • Spark
        • Spark:使用Spark Shell的两个示例
    • Linux
      • Notes
        • BuildInCommand
          • ls
          • ip
          • ftp
          • 目录栈操作
          • scp
          • expect
            • expect示例
            • expect手册
            • expect笔记
          • ps
          • vsftpd
          • wget
          • 压缩程序
            • zip_unzip
            • tar
            • p7zip
          • 部署web服务
          • avidemux
          • cat
          • Awk
          • find
          • pssh使用
          • grep
          • sed
          • 路径
          • 通用命令
          • 安装JDK
          • 进程管理
          • network
          • rsync
          • cron
          • 示例
          • 用户管理
          • supervisor
        • Common
        • TestFileProcess
          • 替换文件内容
        • Commonds
        • Permissions
      • Ubuntu
        • Ubuntu 服务器配置部署
        • Ubuntu笔记
        • Ubuntu网络配置
        • Ubuntu 16.04 几个国内源
      • Script
        • ShellProgramming
        • ShellExamples
        • ShellCommands
      • CentOS
        • Centos笔记
        • 源
        • CentOS-Network-Config
        • CentOS-Security
      • Squid
        • BuildByDocker
        • Squid
      • Problem
        • 常见错误
      • Linux
        • Linux-c-cpp
        • Linux
        • Linux-NetworkProgramming
      • Codes
        • cron-test-01
      • Software
        • Shortcut key
        • Anaconda
      • Make
        • tricks
      • Deepin
        • 安装docker
      • SRE
        • CommonCommand
    • Cloud Computing
      • OpenStack
        • Fuel离线安装OpenStack
        • 验证网络
        • OpenStackNotes
    • Network
      • TCP/IP
      • 套接字
      • OSI模型
    • Data mining
      • StartUp
    • Machine Learning
      • Notes
        • 决策树学习-周志华
        • 神经网络-周志华
        • 概念学习和一般到特殊序
        • MachineLearningProblems
        • Math
          • 概率论与数理统计
          • 数学概念
          • KKT条件
          • 最优化问题
          • 优化算法
          • 最小二乘
        • 模型评估与选择
        • 引言
        • 过拟合处理
        • StatisticalLearningMethod
          • 统计学习方法概论
          • 感知机
        • 评估假设
        • Code
          • FeatureEngineering
            • Iris
        • 概念
        • SVM
        • FeatureEngineering
        • 神经网络
        • 决策树学习
        • MachineLearningKnowledge
        • 线性模型
        • 术语概念
        • 拉格朗日乘子法
      • route
      • Jupyter
        • JupyterUsage
      • Anaconda
        • AnacondaUsage
      • Coursera
        • Week01
      • ScikitLearn
        • FitTransform
        • Preprocessing
      • Octave
        • Octave
    • Search
      • Lucene
        • Api
        • Concepts
    • Virtualization Tech
      • Docker
        • dockerNetwork
        • Ubuntu
        • DockerUsage
        • Mac OS
    • Database
      • MySQL
        • Mysql Cluster
        • mysql-cluster
        • mysql
      • 部署phpmyadmin
      • SQL
      • SQL
        • SQLStatement
    • Concepts
      • Other
      • Mohout
      • LDA
    • Distributed System
      • Concepts
        • TODO
        • TODO
    • Recommend System
      • DataPipline
        • DataBus
        • 系统
    • OS
      • OS-Code
      • Notes
        • Introduce
        • ProcessManagement
        • Kernel
    • Deep Learning
      • Code
        • README
      • Notes
        • Conceptions
        • 神经网络
        • LeNet5
        • CNN
      • Tensorflow
        • Notes
          • Tensorflow
          • tensorflow开始
        • Anaconda
    • Media
      • FFmpeg
        • LiveStream
          • run
    • Spider
      • Selenium
        • Selenium
    • IoT
      • emq
        • Authentication
    • Big Data
      • Hadoop
        • MR 作业
  • Architecture
    • Storage
      • Mongodb
        • Mongodb
        • Failed to unlink socket file
      • Pegasus
        • Pegasus
        • ShellTools
      • Rocksdb
        • RocksJava
        • RocksDB
        • 本地缓存
      • Redis
        • Install
        • RedisUsage
      • 基本要素
      • HBase
        • HBase
    • MQ
      • Kafka
        • VersionCompare
        • Deploy
        • cppkafka
        • CommandLineTools
        • OffsetManage
        • Attentions
        • Notes
        • QA
    • Framework
      • Java
        • Dubbo
          • Annotation
          • 简介
        • Spring
          • SpringTest
          • 常见错误
          • TransactionRollback
          • FileUpload
          • SpringMVCNote
          • IoC
          • Start
          • Notes
            • Config
          • Spring
          • springmvc
          • Modules
        • Rose
          • Get request body
        • Netty
          • Netty
        • SpringBoot
          • SpringBoot
      • Esper
        • Documents
          • Keyed Segmented Context
          • 01 - Getting Started
          • 02 - Event Representations
          • 03 - Processing Modal
      • Swagger
        • Swagger
    • RPC
      • Thrift
        • Notes
          • Set fields
          • ThriftTyps
        • BuildFromSource
        • ThriftUsage
        • Install
      • ProtocolBuffer
        • 减少内存拷贝
        • UsageExample
        • Arena
        • ProtocolBuffer
    • Distribution
      • CAP
    • Streaming
      • Spark
        • Init
      • MapReduce
      • Spark
    • Nginx
      • Nginx knowledge
      • nginx-configurtion
      • 403
      • nginx解析php文件时502
    • Governance
      • Consul
      • Zookeeper
        • Zookeeper
      • MicroServiceArchitecture
      • 依赖
    • Conceptions
      • CloudNative
    • Kibana
      • Query
    • Performance Optimizaition
      • Notes
        • Conceptions
        • CPUAffinity
  • Math
    • Probability Theory
      • 一些概率分布
    • Statistics
      • 统计量与估计量
    • Other
      • 排列组合
  • Tools
    • Markdown
      • syntax
    • Jetbrains
      • Jetbrains
    • Zsh
      • Install
  • TODO
由 GitBook 提供支持
在本页
  • 工厂模式
  • 依赖倒置原则
  • 引言
  • 简单工厂方法
  • 工厂方法模式
  • 抽象工厂模式
  • 比较工厂方法模式和抽象工厂模式
  • 总结
  • 案例
  • 披萨工厂

这有帮助吗?

  1. Coding
  2. Design Pattern

设计模式笔记_四_工厂模式

[TOC]

工厂模式

  • 工厂方法模式

  • 抽象工厂模式

工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这样,客户程序中关于超类的代码就和子类对象创建代码解耦了。

所有工厂模式都用来封装对象的创建。

依赖倒置原则

依赖倒置: 要依赖抽象,不要依赖具体类。

不能让高层组件依赖低层组件,而且,不管高层组件或低层组件,两者都应该依赖于抽象。

在依赖导致原则中, 倒置指的是和一般OO设计的思考方式完全相反。

技巧

避免在OO设计中违反依赖倒置原则的技巧:

  • 变量不可以持有具体类的引用。如果使用new,就会持有具体类的引用。可以改用工厂来避开这样的做法。

  • 不要让类派生自具体类。如果派生自具体类,就会依赖具体类。应该派生自一个抽象(接口或抽象类)。

  • 不要覆盖基类中已实现的方法。如果覆盖基类已实现的方法,那么基类就不是一个真正适合被继承的抽象。基类中以实现的方法,应该由所有子类共享。

引言

我们不应该针对实现编程,但是当我们每次使用new时,就会想到“具体”。使用new时,的确是在实例化一个具体类,所以用的确实是实现,而不是接口。我们知道,代码绑定具体类会导致代码更脆弱,更缺乏弹性。

当看到这样的代码,一旦有变化或扩展,就必须重新打开这段代码进行检查和修改。通常这样修改过的代码将造成部分系统更难维护和更新,而且也更容易犯错。

针对接口编程,可以隔离掉以后系统可能发生的一大堆改变。因为,如果代码是针对接口而写,那么通过多态,它可以与任何新类实现该接口。

当代码使用大量具体类时,一旦进入新的具体类,就必须改变代码。也就是说,你的代码并非“对修改关闭”。

解决上述问题,就需要“找出会变的方面,把它们从不变的部分分离出来”。

简单工厂方法

  • 算不上设计模式(依据《Head First 设计模式》)

  • 简单工厂模式属于创建型模式

  • 又叫做静态工厂方法

  • 简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例

  • 实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类

角色及职责

  • 工厂(Creator)角色: 简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。

  • 抽象产品(Product)角色: 简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。

  • 具体产品(Concrete Product)角色: 是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。

优缺点

优点

  • 明确了各自的职责和权利,有利于整个软件体系结构的优化。

缺点

  • 违反了高内聚责任分配原则。如果添加新类,则需要改变工厂类。

示例

参考案例中披萨工厂简单工厂阶段。

工厂方法模式

定义

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

工厂方法模式(Factory Method Pattern)通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。

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

工厂方法模式不过是,通过子类来创建对象。

工厂方法:用来创建对象的方法。

优点

  • 工厂模式帮助我们将产品的实现从使用中解耦。如果增加产品或者改变产品的实现,Creator并不会受到影响(因为Creator与任何ConcreteProduct之间都不是紧耦合)。

  • 创建对象的代码集中在一个对象或方法中,可以避免代码中的重复,并且更方便以后的维护

  • 客户在实例化对象时,只会依赖于接口,而不是具体类

  • 可以帮助我们针对接口编程,而不是针对实现编程。这让代码更具有弹性,可以应对未来的扩展

  • 封装起创建对象的代码,就可以对抽象编码,将客户代码和实现代码解耦

组成元素

  • 创建者(Creator)类

  • 产品类

平行的类层级

抽象工厂模式

定义

抽象工厂模式 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么。这样一来,客户就从具体的产品中被解耦。

类图

比较工厂方法模式和抽象工厂模式

工厂方法模式潜伏在抽象工厂模式中。抽象工厂的方法经常以工厂方法的方式实现。抽象工厂的任务是定义一个负责创建一组产品的接口。这个接口内的每个方法都负责创建一个具体产品,同时我们利用实现抽象工厂的子类来提供这些具体的做法。

工厂方法模式和抽象工厂模式,都用来负责创建对象,都可以把应用程序从特定实现中解耦,只是做法不同:

  • 工厂方法模式:

    • 使用的是类,利用的方法是继承。

    • 整个工厂方法,只不过是通过子类来创建对象。用这种做法,客户只需要知道他们所使用的抽象类型就可以了,而由子类来负责决定具体类型。换句话说,工厂方法模式只负责将客户从具体类型中解耦。

    • 可以把客户代码从需要实例化的具体类中解耦。

    • 相对简单,只要继承为子类,并实现工厂方法即可。

  • 抽象工厂模式:

    • 通过对象的组合实现解耦。

    • 提供一个用来创建一个产品家族的抽象类型,这个类型的子类定义了产品被产生的方法。要想使用这个工厂,必须先实例化它,然后将它传入一些针对抽象类型所写的代码中。所以,和工厂方法一样,抽象工厂可以吧客户从所使用的实际具体产品中解耦。

    • 此外,还可以把一群相关的产品集合起来。但是,如果需要扩展这组产品,需要修改接口。

    • 当需要创建产品家族,并想让制造的相关产品集合起来时使用。

类图对比

以披萨店为例

工厂方法模式

总结

工具

基础

  • 抽象

  • 封装

  • 多态

  • 继承

原则

  • 多用组合,少用继承

  • 针对接口编程,不针对实现编程

  • 为交互对象之间的松耦合设计而努力

  • 类应该对扩展开放,对修改关闭

  • 依赖抽象,不要依赖具体

设计模式

  • 抽象工厂模式

  • 工厂方法模式

要点

  • 所有的工厂都是用来封装对象的创建

  • 简单工厂,虽然不是真正的设计模式,但扔不失为一个简单的方法,可以将客户程序从具体类解耦

  • 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象

  • 抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中

  • 所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合

  • 工厂方法允许类将实例化延迟到子类进行

  • 抽象工厂创建相关的对象家族,而不需要依赖他们的具体类

  • 依赖倒置原则,指导我们避免依赖具体类型,而要尽量依赖抽象

  • 工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体类编程

案例

披萨工厂

简单工厂阶段

识别变化的方面

假如你有一个披萨店,你的代码可能这样写:

如果需要更多的披萨类型,则需要增加代码,来决定适合的比萨类型,然后再制造这个披萨:

如果,此时,披萨的类型发生了很多变化:

很明显,实例化某些具体类,将使orderPizza()出问题,而且也无法让orderPizza()对修改关闭。但是,我们已经知道了那些地方会改变,那些地方不会,接下来就是使用封装的时候了。

封装变化的部分

建立简单的工厂

定义一个类,为所有比萨封装创建对象的代码:

几个疑惑:

重做PizzaStore类

使用披萨工厂来,修改客户代码:

简单工厂阶段总结

  • 简单工厂其实不是一个设计模式,反而像是一种编程习惯

使用简单工厂方法,实现的披萨店类图:

在设计模式中,“实现一个接口”并“不一定”表示“写一个类,并利用implements关键词来实现某个接口”。“实现一个接口”泛指实现某个超类型(可以是类或接口)的某个方法。

工厂方法模式阶段

加盟披萨店

一种做法

利用SimplePizzaFactory,写出三种不同的工厂,分别是NYPizzaFactory、ChicagoPizzaFactory、CaliforniaPizzaFactory。

然后,变成这个样子:

加盟店采用你的工厂创建披萨,但在其他部分,他们想采用自创的流程:烘烤的做法有差异、不要切片等。

稍早的SimplePizzaFactory,制作披萨的代码绑在PizzaStore内,这么做没有弹性,导致上述需求不能满足。

另一种方法

给披萨店使用框架。有个做法可让披萨活动限制在PizzaStore类(之所以成为加盟店,必须要满足的),又同时能让加盟店可以自由地制作该区域的风味披萨。

所要做的事就是,把createPizza()方法放回PizzaStore内,不过要把它设置为抽象方法,最后为每个区域风味创建一个PizzaStore的子类。

PizzaStore超类

现在有了PizzaStore超类,让每个区域类型9(NYPizzaStore、ChicagoPizzaStore、CaliforniaPizzaStore)都继承这个PizzaStore,每个子类各自决定如何制造披萨。

允许子类做决定

我们已经知道:

  • PizzaStore已经有一个不错的订单系统,由orderPizza()方法负责处理订单,你希望所有加盟店都可以使用这个完善的系统

  • 还需要允许加盟店之间制作披萨的差异,让createPizza()能够对这些变化来负责创建正确种类的披萨。

我们的做法是:让PizzaStore的各个子类负责定义自己的createPizza()方法。我们会得到一些PizzaStore具体的子类,每个子类都有自己的披萨变体,而仍然适合PizzaStore框架,并使用orderPizza()方法。

开一家披萨店吧

这是一家纽约风味的披萨店:

声明一个工厂方法

原本由一个对象负责所有具体类的实例化,现在通过对PizzaStore做一些小转变,变成由一群子类来负责实例化:

订购披萨

根据订单生产披萨

代码

Pizza

import java.util.ArrayList;

/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 披萨抽象超类
 */
public abstract class Pizza {
    String name;
    String dough;
    String sauce;
    ArrayList toppings = new ArrayList();

    void prepare() {
        System.out.println("Preparing " + name);
        System.out.println("Tossing dough...");
        System.out.println("Adding sauce...");
        System.out.println("Adding toppings: ");        
        for (int i=0; i < toppings.size(); ++i) {
            System.out.println("   " + toppings.get(i));
        }
    }

    void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }

    void cut() {
        System.out.println("Cutting the pizza into diagonal slices");
    }

    void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }

    public String getName() {
        return name;
    }
}

PizzaStore

/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 工厂类
 */
public abstract class PizzaStore {
    public Pizza orderPizza(String type) {
        Pizza pizza;

        pizza = createPizza(type);

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }

    abstract Pizza createPizza(String type);
}
/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 芝加哥披萨店
 */
public class ChicagoPizzaStore extends PizzaStore {
    Pizza createPizza(String item) {
        if (item.equals("cheese")) {
            return new ChicagoStyleCheesePizza();
        } else if (item.equals("veggie")) {
            return new ChicagoStyleVeggiePizza();
        } else if (item.equals("clam")) {
            return new ChicagoStyleClamPizza();
        } else if (item.equals("pepperoni")) {
            return new ChicagoStylePepperoniPizza();
        } else return null;
    }
}
/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 披萨具体类
 */
public class ChicagoStyleCheesePizza extends Pizza {

    public ChicagoStyleCheesePizza() { 
        name = "Chicago Style Deep Dish Cheese Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";

        toppings.add("Shredded Mozzarella Cheese");
    }

    void cut() {
        System.out.println("Cutting the pizza into square slices");
    }
}
/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 披萨具体类
 */
public class ChicagoStyleClamPizza extends Pizza {
    public ChicagoStyleClamPizza() {
        name = "Chicago Style Clam Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";

        toppings.add("Shredded Mozzarella Cheese");
        toppings.add("Frozen Clams from Chesapeake Bay");
    }

    void cut() {
        System.out.println("Cutting the pizza into square slices");
    }
}
/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 披萨具体类
 */
public class ChicagoStylePepperoniPizza extends Pizza {
    public ChicagoStylePepperoniPizza() {
        name = "Chicago Style Pepperoni Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";

        toppings.add("Shredded Mozzarella Cheese");
        toppings.add("Black Olives");
        toppings.add("Spinach");
        toppings.add("Eggplant");
        toppings.add("Sliced Pepperoni");
    }

    void cut() {
        System.out.println("Cutting the pizza into square slices");
    }
}
/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 披萨具体类
 */
public class ChicagoStyleVeggiePizza extends Pizza {
    public ChicagoStyleVeggiePizza() {
        name = "Chicago Deep Dish Veggie Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";

        toppings.add("Shredded Mozzarella Cheese");
        toppings.add("Black Olives");
        toppings.add("Spinach");
        toppings.add("Eggplant");
    }

    void cut() {
        System.out.println("Cutting the pizza into square slices");
    }
}
/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 纽约披萨店
 */
public class NYPizzaStore extends PizzaStore {
    Pizza createPizza(String item) {
        if (item.equals("cheese")) {
            return new NYStyleCheesePizza();
        } else if (item.equals("veggie")) {
            return new NYStyleVeggiePizza();
        } else if (item.equals("clam")) {
            return new NYStyleClamPizza();
        } else if (item.equals("pepperoni")) {
            return new NYStylePepperoniPizza();
        } else return null;
    }
}
/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 披萨具体类
 */
public class NYStyleCheesePizza extends Pizza {
    public NYStyleCheesePizza() {
        name = "NY Style Sauce and Cheese Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";

        toppings.add("Grated Reggiano Cheese");
    }
}
/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 披萨具体类
 */
public class NYStyleClamPizza extends Pizza {

    public NYStyleClamPizza() {
        name = "NY Style Clam Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";

        toppings.add("Grated Reggiano Cheese");
        toppings.add("Fresh Clams from Long Island Sound");
    }
}
/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 披萨具体类
 */
public class NYStylePepperoniPizza extends Pizza {

    public NYStylePepperoniPizza() {
        name = "NY Style Pepperoni Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";

        toppings.add("Grated Reggiano Cheese");
        toppings.add("Sliced Pepperoni");
        toppings.add("Garlic");
        toppings.add("Onion");
        toppings.add("Mushrooms");
        toppings.add("Red Pepper");
    }
}
/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 披萨具体类
 */
public class NYStyleVeggiePizza extends Pizza {

    public NYStyleVeggiePizza() {
        name = "NY Style Veggie Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";

        toppings.add("Grated Reggiano Cheese");
        toppings.add("Garlic");
        toppings.add("Onion");
        toppings.add("Mushrooms");
        toppings.add("Red Pepper");
    }
}

PizzaTestDrive

/**
 * 设计模式 - 工厂模式
 * PizzaStore
 * 测试类
 */
public class PizzaTestDrive {
    public static void main(String[] args) {
        PizzaStore nyStore = new NYPizzaStore();
        PizzaStore chicagoStore = new ChicagoPizzaStore();

        Pizza pizza = nyStore.orderPizza("cheese");
        System.out.println("Ethan ordered a " + pizza.getName() + "\n");

        pizza = chicagoStore.orderPizza("cheese");
        System.out.println("Joel ordered a " + pizza.getName() + "\n");
    }
}

输出

Preparing NY Style Sauce and Cheese Pizza
Tossing dough...
Adding sauce...
Adding toppings:
   Grated Reggiano Cheese
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a NY Style Sauce and Cheese Pizza

Preparing Chicago Style Deep Dish Cheese Pizza
Tossing dough...
Adding sauce...
Adding toppings:
   Shredded Mozzarella Cheese
Bake for 25 minutes at 350
Cutting the pizza into square slices
Place pizza in official PizzaStore box
Joel ordered a Chicago Style Deep Dish Cheese Pizza

小结

  • 实际应用中,应该把披萨类型的类型从String改为静态变量或者enum类型。

抽象工厂模式阶段

原料有了新需求

后来,披萨原料又有了新的需求...

我们需要建立原料工厂,来保证披萨的质量。可是,名称相同的原料,不同的地方,也是不一样了...

每个区域,对相同原料,有不同实现。

原料家族

建造原料工厂

为每个区域建造一个工厂。首先,为原料工厂定义一个接口,负责创建所有的原料。

/**
 * 设计模式 - 抽象工厂模式
 * 原料工厂接口
 */
public interface PizzaIngredientFactory {
    // 在接口中,每个原料都有一个对应的方法创建该原料

    public Dough createDough();
    public Sauce createSauce();
    public Cheese createCheese();
    public Veggies[] createVeggies();
    public Pepperoni createPepperoni();
    public Clams createClam();
}

创建纽约原料工厂

重做披萨基类

重做披萨实现类

重新设计披萨店

究竟做了什么...

现在的订单完成过程

  • 首先需要一个纽约披萨店

    PizzaStore nyPizzaStore = new NYPizzaStore();
  • 现在已经有一个披萨店了,可以接受订单:

    nyPizzaStore.orderPizza("cheese");
  • orderPizza()方法首先调用createPizza()方法:

    Pizza pizza = createPizza("cheese");
  • 当createPizza()方法被调用时,也就可是设计原料工厂了

    Pizza pizza = new CheesePizza(nyIngredientFactory);    // 选择原料工厂,接着在PizzaStore中实例化,然后将它传进每个披萨的构造器中
  • 接下来需要准备披萨。一旦调用prepare()方法,工厂将被要求准备原料:

    void prepare() {
        dough = factory.createDough();
          sauce = factory.createSauce();
          cheese = facotry.createCheese();
    }
  • 最后,得到了准备好的披萨,orderPizza()就会接着烘焙、切片、装盒。

类图

上一页Design Pattern下一页设计模式笔记_六_命令模式

最后更新于4年前

这有帮助吗?