JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式)

2023-05-16

jason0539转载 链接地址http://blog.csdn.net/jason0539


在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些情况下, new操作符直接生成对象会带来一些问题。举例来说, 许多类型对象的创造需要一系列的步骤: 你可能需要计算或取得对象的初始设置; 选择生成哪个子对象实例; 或在生成你需要的对象之前必须先生成一些辅助功能的对象。 在这些情况,新对象的建立就是一个 “过程”,不仅是一个操作,像一部大机器中的一个齿轮传动。

模式的问题:你如何能轻松方便地构造对象实例,而不必关心构造对象实例的细节和复杂过程呢?

解决方案:建立一个工厂来创建对象

实现:

一、引言
    1)还没有工厂时代:假如还没有工业革命,如果一个客户要一款宝马车,一般的做法是客户去创建一款宝马车,然后拿来用。
    2)简单工厂模式:后来出现工业革命。用户不用去创建宝马车。因为客户有一个工厂来帮他创建宝马.想要什么车,这个工厂就可以建。比如想要320i系列车。工厂就创建这个系列的车。即工厂可以创建产品。
    3)工厂方法模式时代:为了满足客户,宝马车系列越来越多,如320i,523i,30li等系列一个工厂无法创建所有的宝马系列。于是由单独分出来多个具体的工厂。每个具体工厂创建一种系列。即具体工厂类只能创建一个具体产品。但是宝马工厂还是个抽象。你需要指定某个具体的工厂才能生产车出来。

   4)抽象工厂模式时代:随着客户的要求越来越高,宝马车必须配置空调。于是这个工厂开始生产宝马车和需要的空调。

   最终是客户只要对宝马的销售员说:我要523i空调车,销售员就直接给他523i空调车了。而不用自己去创建523i空调车宝马车.

   这就是工厂模式。

二、分类 
        工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。 
工厂模式可以分为三类: 

1)简单工厂模式(Simple Factory) 
2)工厂方法模式(Factory Method) 
3)抽象工厂模式(Abstract Factory) 

 这三种模式从上到下逐步抽象,并且更具一般性。 
        GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。

        将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。 

三、区别 
工厂方法模式:
一个抽象产品类,可以派生出多个具体产品类。   
一个抽象工厂类,可以派生出多个具体工厂类。   
每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。   
一个抽象工厂类,可以派生出多个具体工厂类。   
每个具体工厂类可以创建多个具体产品类的实例。   
区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。   
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
两者皆可。 

 四、简单工厂模式 
建立一个工厂(一个函数或一个类方法)来制造新的对象。
分布说明引子:从无到有。客户自己创建宝马车,然后拿来用。

 

 

public class BMW320 {
	public BMW320(){
		System.out.println("制造-->BMW320");
	}
}

public class BMW523 {
	public BMW523(){
		System.out.println("制造-->BMW523");
	}
}

public class Customer {
	public static void main(String[] args) {
		BMW320 bmw320 = new BMW320();
		BMW523 bmw523 = new BMW523();
	}
}

客户需要知道怎么去创建一款车,客户和车就紧密耦合在一起了.为了降低耦合,就出现了工厂类,把创建宝马的操作细节都放到了工厂里面去,客户直接使用工厂的创建工厂方法,传入想要的宝马车型号就行了,而不必去知道创建的细节.这就是工业革命了:简单工厂模式

即我们建立一个工厂类方法来制造新的对象。如图:

产品类:

abstract class BMW {
	public BMW(){
		
	}
}

public class BMW320 extends BMW {
	public BMW320() {
		System.out.println("制造-->BMW320");
	}
}
public class BMW523 extends BMW{
	public BMW523(){
		System.out.println("制造-->BMW523");
	}
}

工厂类:

public class Factory {
	public BMW createBMW(int type) {
		switch (type) {
		
		case 320:
			return new BMW320();

		case 523:
			return new BMW523();

		default:
			break;
		}
		return null;
	}
}


客户类:

public class Customer {
	public static void main(String[] args) {
		Factory factory = new Factory();
		BMW bmw320 = factory.createBMW(320);
		BMW bmw523 = factory.createBMW(523);
	}
}

   简单工厂模式又称静态工厂方法模式。重命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。 
      先来看看它的组成: 
         1) 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品
         2) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。         
         3) 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。 
        
        下面我们从开闭原则(对扩展开放;对修改封闭)上来分析下简单工厂模式。当客户不再满足现有的车型号的时候,想要一种速度快的新型车,只要这种车符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。所以对产品部分来说,它是符合开闭原则的;但是工厂部分好像不太理想,因为每增加一种新型车,都要在工厂类中增加相应的创建业务逻辑(createBMW(int type)方法需要新增case),这显然是违背开闭原则的。可想而知对于新产品的加入,工厂类是很被动的。对于这样的工厂类,我们称它为全能类或者上帝类。 
        我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝累坏了,也累坏了我们这些程序员。
        于是工厂方法模式作为救世主出现了。 工厂类定义成了接口,而每新增的车种类型,就增加该车种类型对应工厂类的实现,这样工厂的设计就可以扩展了,而不必去修改原来的代码。
五、工厂方法模式 
        工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。 
工厂方法模式组成: 
       1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。 
       2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。 
       3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。 
       4)具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。 
       工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活 起来——当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有 的代码。可以看出工厂角色的结构也是符合开闭原则的! 

代码如下: 

产品类:

abstract class BMW {
	public BMW(){
		
	}
}
public class BMW320 extends BMW {
	public BMW320() {
		System.out.println("制造-->BMW320");
	}
}
public class BMW523 extends BMW{
	public BMW523(){
		System.out.println("制造-->BMW523");
	}
}


创建工厂类:

interface FactoryBMW {
	BMW createBMW();
}

public class FactoryBMW320 implements FactoryBMW{

	@Override
	public BMW320 createBMW() {

		return new BMW320();
	}

}
public class FactoryBMW523 implements FactoryBMW {
	@Override
	public BMW523 createBMW() {

		return new BMW523();
	}
}


客户类:

public class Customer {
	public static void main(String[] args) {
		FactoryBMW320 factoryBMW320 = new FactoryBMW320();
		BMW320 bmw320 = factoryBMW320.createBMW();

		FactoryBMW523 factoryBMW523 = new FactoryBMW523();
		BMW523 bmw523 = factoryBMW523.createBMW();
	}
}


 工厂方法模式仿佛已经很完美的对对象的创建进行了包装,使得客户程序中仅仅处理抽象产品角色提供的接口,但使得对象的数量成倍增长。当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。

参考http://blog.csdn.net/hguisu/article/details/7505909


以上就是简单工厂模式,工厂方法模式


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式) 的相关文章

  • JAVA语言之基数排序

    基数排序简而言之可以创建0 9余数共十个桶 代码如下 xff1a public class jishu 1 public static void main String args int A 61 new int 54 35 48 36 2
  • 链式A+B之程序员面试经典

    有两个用链表表示的整数 xff0c 每个结点包含一个数位 这些数位是反向存放的 xff0c 也就是个位排在链表的首部 编写函数对这两个整数求和 xff0c 并用链表形式返回结果 给定两个链表ListNode A xff0c ListNode
  • Android逆向【4】:暴力破解APK签名校验,愉快的重新打包微信支付宝APK

    回顾 Android逆向小技巧 xff1a 批量注入日志 xff0c 打印目标程序执行流程 在上一篇2019年的文章中 xff0c 我们使用python写了一个简单的文本处理工具 xff1a https github com encoder
  • Anaconda相关shell命令相关知识点

    文章目录 前言一 Anaconda或Miniconda镜像下载二 配置Anaconda源1 查看安装过的镜像1 显示镜像源 xff0c 如果是新安装Anaconda则默认使用国外镜像源 xff0c 它会显示2 若有新的镜像源 xff0c 它
  • 回文链表之程序员面试经典

    题目描述 请编写一个函数 xff0c 检查链表是否为回文 给定一个链表ListNode pHead xff0c 请返回一个bool xff0c 代表链表是否为回文 测试样例 xff1a 1 2 3 2 1 返回 xff1a true 1 2
  • 集合栈之程序员面试经典

    题目描述 请实现一种数据结构SetOfStacks xff0c 由多个栈组成 xff0c 其中每个栈的大小为size xff0c 当前一个栈填满时 xff0c 新建一个栈 该数据结构应支持与普通栈相同的push和pop操作 给定一个操作序列
  • JAVA语言之全排列的递归实现

    问题 xff1a 假如有一个数组的值为1 2 2 3 4 5一共六个值 xff0c 进行全排列 xff0c 但要求是3和5不能在一起 xff0c 并且4不能在第三个位置 代码如下 public class testtest public s
  • 猫狗收容所之程序员面试经典

    题目描述 有家动物收容所只收留猫和狗 xff0c 但有特殊的收养规则 xff0c 收养人有两种收养方式 xff0c 第一种为直接收养所有动物中最早进入收容所的 xff0c 第二种为选择收养的动物类型 xff08 猫或狗 xff09 xff0
  • 双栈排序之程序员面试经典

    题目描述 请编写一个程序 xff0c 按升序对栈进行排序 xff08 即最大元素位于栈顶 xff09 xff0c 要求最多只能使用一个额外的栈存放临时数据 xff0c 但不得将元素复制到别的数据结构中 给定一个int numbers C 4
  • 用两个栈实现队列之程序员面试经典

    题目描述 用两个栈来实现一个队列 xff0c 完成队列的Push和Pop操作 队列中的元素为int类型 比如有栈A和栈B xff0c 在模拟队列的时候先将所有数据依次放入栈A中 xff0c 在要弹出的时候将A中的数据依次从上到下放进栈B x
  • 高度最小的BST之程序员面试经典

    题目描述 对于一个元素各不相同且按升序排列的有序序列 xff0c 请编写一个算法 xff0c 创建一棵高度最小的二叉查找树 给定一个有序序列int vals 请返回创建的二叉查找树的高度 二叉排序树 xff08 Binary Sort Tr
  • 二叉树平衡检查之程序员面试经典

    题目描述 实现一个函数 xff0c 检查二叉树是否平衡 xff0c 平衡的定义如下 xff0c 对于树中的任意一个结点 xff0c 其两颗子树的高度差不超过1 给定指向树根结点的指针TreeNode root xff0c 请返回一个bool
  • JAVA语言之三色排序

    有一个只由0 xff0c 1 xff0c 2三种元素构成的整数数组 xff0c 请使用交换 原地排序而不是使用计数进行排序 给定一个只含0 xff0c 1 xff0c 2的整数数组A 及它的大小 xff0c 请返回排序后的数组 保证数组大小
  • Linux 服务器下载并安装jdk8 学习教程

    获得一台linux服务器 要在linux下安装jdk xff0c 首先你得先有一台linux服务器 xff0c 虚拟机或者租一台都可以 yum安装jdk xff08 力荐 xff09 在linux上使用yum安装是非常粗暴无脑的 xff0c
  • JAVA语言之有序矩阵查找

    现在有一个行和列都排好序的矩阵 xff0c 请设计一个高效算法 xff0c 快速查找矩阵中是否含有值x 给定一个int矩阵mat xff0c 同时给定矩阵大小n xm 及待查找的数x xff0c 请返回一个bool值 xff0c 代表矩阵中
  • JAVA语言之最短子数组长度

    对于一个数组 xff0c 请设计一个高效算法计算需要排序的最短子数组的长度 给定一个int数组A 和数组的大小n xff0c 请返回一个二元组 xff0c 代表所求序列的长度 原序列位置从0开始标号 若原序列有序 xff0c 返回0 保证A
  • JAVA语言之相邻两数最大差值

    有一个整形数组A xff0c 请设计一个复杂度为O n 的算法 xff0c 算出排序后相邻两数的最大差值 给定一个int数组A 和A 的大小n xff0c 请返回最大的差值 保证数组元素多于1个 测试样例 xff1a 1 2 5 4 6 5
  • Spring MVC 流程图

    Spring MVC工作流程图 图一 图二 Spring工作流程描述 1 用户向服务器发送请求 xff0c 请求被Spring 前端控制Servelt DispatcherServlet捕获 xff1b 2 DispatcherServle
  • 输出单层结点之程序员面试经典

    题目描述 对于一棵二叉树 xff0c 请设计一个算法 xff0c 创建含有某一深度上所有结点的链表 给定二叉树的根结点指针TreeNode root xff0c 以及链表上结点的深度 xff0c 请返回一个链表ListNode xff0c
  • java中没有2进制的数据类型,对二进制的操作,需要使用共三种操作符

    lt lt 左移位操作符 gt gt 右移位操作符 gt gt gt 无符号右移操作符 使用左移时 xff0c 数会变大 xff0c 很多时间 xff0c 用来代替 乘方 的操作 比如 2的平方 61 2 2 61 4 61 2 lt lt

随机推荐

  • 面向对象的特征有哪些方面

    需要学习资料的 43 微信公众号 学习资源后台找我 本人比较忙 我看到了会在后台帮你 xff0c 谢谢关注啦 抽象 xff1a 抽象是将一类对象的共同特征总结出来构造类的过程 xff0c 包括数据抽象和行为抽象两方面 抽象只关注对象有哪些属
  • 句子的逆序

    对于一个字符串 xff0c 请设计一个算法 xff0c 只在字符串的单词间做逆序调整 xff0c 也就是说 xff0c 字符串由一些由空格分隔的部分组成 xff0c 你需要将这些部分逆序 给定一个原字符串A 和他的长度 xff0c 请返回逆
  • 字符串移位

    对于一个字符串 xff0c 请设计一个算法 xff0c 将字符串的长度为len的前缀平移到字符串的最后 给定一个字符串A 和它的长度 xff0c 同时给定len xff0c 请返回平移后的字符串 测试样例 xff1a 34 ABCDE 34
  • 拼接最小字典序

    对于一个给定的字符串数组 xff0c 请找到一种拼接顺序 xff0c 使所有小字符串拼接成的大字符串是所有可能的拼接中字典序最小的 给定一个字符串数组strs xff0c 同时给定它的大小 xff0c 请返回拼接成的串 测试样例 xff1a
  • go语言时间类型和时间戳

    时间类型 获取当地时间 fmt span class token punctuation span span class token function Println span span class token punctuation sp
  • 是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?

    不可以 xff0c 静态方法只能访问静态成员 xff0c 因为非静态方法的调用要先创建对象 xff0c 在调用静态方法时可能对象并没有被初始化
  • GC是什么?为什么要有GC?

    GC 是垃圾收集的意思 xff0c 内存处理是编程人员容易出现问题的地方 xff0c 忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃 xff0c Java 提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的 xf
  • 空格替换

    请编写一个方法 xff0c 将字符串中的空格全部替换为 20 假定该字符串有足够的空间存放新增的字符 xff0c 并且知道字符串的真实长度 小于等于1000 xff0c 同时保证字符串由大小写的英文字母组成 给定一个string iniSt
  • 合法括号序列判断

    对于一个字符串 xff0c 请设计一个算法 xff0c 判断其是否为一个合法的括号串 给定一个字符串A 和它的长度n xff0c 请返回一个bool值代表它是否为一个合法的括号串 测试样例 xff1a 34 34 6 返回 xff1a tr
  • 最长无重复字符子串

    对于一个字符串 请设计一个高效算法 xff0c 找到字符串的最长无重复字符的子串长度 给定一个字符串A 及它的长度n xff0c 请返回它的最长无重复字符子串长度 保证A中字符全部为小写英文字符 xff0c 且长度小于等于500 测试样例
  • 列出一些你常见的运行时异常(非检查异常)?

    ArithmeticException xff08 算术异常 xff09 ClassCastException xff08 类转换异常 xff09 IllegalArgumentException xff08 非法参数异常 xff09 In
  • 阐述final、finally、finalize的区别

    final xff1a 修饰符 xff08 关键字 xff09 有三种用法 xff1a 如果一个类被声明为final xff0c 意味着它不能再派生出新的子类 xff0c 即不能被继承 xff0c 因此它和abstract是反义词 将变量声
  • 检查是否为BST

    题目描述 请实现一个函数 xff0c 检查一棵二叉树是否为二叉查找树 给定树的根结点指针TreeNode root xff0c 请返回一个bool xff0c 代表该树是否为二叉查找树 代码如下 xff1a package com mian
  • 线程的sleep()方法和yield()方法有什么区别?

    需要学习资料的 43 微信公众号 学习资源后台找我 本人比较忙 我看到了会在后台帮你 xff0c 谢谢关注啦 sleep 方法给其他线程运行机会时不考虑线程的优先级 xff0c 因此会给低优先级的线程以运行的机会 xff1b yield 方
  • 可查询最值的栈

    定义栈的数据结构 xff0c 请在该类型中实现一个能够得到栈最小元素的min函数 代码如下 xff1a 定义两个栈 xff0c 一个stackData xff0c 一个stackMin 将数组中的元素一个个压入stackData栈的时候 x
  • 归并排序(详解)

    时间复杂度 xff1a O xff08 n logn xff09 空间复杂度 xff1a O xff08 n xff09 归并排序分为拆分和归并两个过程 拆分 xff1a 拆分是一个递归的过程 xff0c 实质是将待排序数组均分再均分 xf
  • 双栈队列

    编写一个类 只能用两个栈结构实现队列 支持队列的基本操作 push xff0c pop 给定一个操作序列ope 及它的长度n xff0c 其中元素为正数代表push操作 xff0c 为0代表pop操作 xff0c 保证操作序列合法且一定含p
  • 在进行数据库编程时,连接池有什么作用?

    由于创建连接和释放连接都有很大的开销 xff08 尤其是数据库服务器不在本地时 xff0c 每次建立连接都需要进行TCP 的三次握手 xff0c 释放连接需要进行TCP四次握手 xff0c 造成的开销是不可忽视的 xff09 为了提升系统访
  • Java 虚拟机 gc算法总结

    一 垃圾收集基本的算法 1 引用计数 Reference Counting 为每一个对象添加一个计数器 xff0c 计数器记录了对该对象的活跃引用的数量 如果计数器为0 xff0c 则说明这个对象没有被任何变量所引用 xff0c 即应该进行
  • JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式)

    从jason0539转载 链接地址http blog csdn net jason0539 在面向对象编程中 最通常的方法是一个new操作符产生一个对象实例 new操作符就是用来构造对象实例的 但是在一些情况下 new操作符直接生成对象会带