java23种设计模式——三、工厂模式
工厂模式
工厂模式介绍
工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。(百度百科)
工厂模式又分为:
- 简单工厂模式:允许接口创建对象,但不会暴露对象的创建逻辑。
- 工厂方法模式: 允许接口创建对象,但使用哪个类来创建对象,则是交由子类决定的
- 抽象方法模式: 抽象工厂是一个能够创建一系列相关的对象而无需指定/公开其具体类的接口。该模式能够提供其他工厂的对象,在其内部创建其他对象。
简单工厂模式
属于创建型模式,又叫做静态工厂方法模式,不属于23种GOF设计模式之一。是由一个工厂对象决定创建出哪一种产品类的实例。违背“开放 - 关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂。
假设现在有一家餐馆
public interface Restaurant {
public void cook();
}
餐馆有两种菜品:红烧肉和鸡蛋羹
//鸡蛋羹
public class Egg implements Restaurant {
@Override
public void cook() {
System.out.println("鸡蛋羹做好了");
}
}
//红烧肉
public class Meet implements Restaurant{
@Override
public void cook() {
System.out.println("红烧肉做好了");
}
}
餐馆里有服务员,来负责向后厨传达客人的需求
public class Waiter {
//同样可以定义常量然后通过switch语句来实现
public static Restaurant getFood(String orderType) {
Restaurant restaurant = null;
if(orderType.equals("红烧肉")){
restaurant = new Meet();
}else if (orderType.equals("鸡蛋羹")){
restaurant = new Egg();
}
return restaurant;
}
}
现在顾客来了,要点一份红烧肉,就只需要和服务员说就行
public class Customer {
public static void main(String[] args) {
Restaurant restaurant = Waiter.getFood("红烧肉");
restaurant.cook();
}
}
输出
红烧肉做好了
通过以上方法,的确实现了 提供创建实例的功能,而无需关心具体实现。但是我们不难发现,这种方法的扩展性很差,如果餐馆新出了一款菜品,还需要我们在服务员方法里修改。这使得当餐馆的菜品很多时,工厂方法代码逻辑将会非常复杂
工厂方法模式
工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。是在工厂模式家族中是用的最多模式,一般项目中存在最多的就是这个模式。是对简单工厂模式的一个优化,让每个对象都有一个与之对应的工厂。
这里我们接着用上面的例子,假设这家餐厅的生意非常好,所以餐馆的老板把餐馆所有负责点餐的服务员都辞退了,取而代之的是添加了一个收银台,然后让每个厨师只负责做一样菜。这样客人只需要和收银台说要求就行了。
这里我们接着用上面的类。除去服务员Waiter类
新建Cashier接口
/**
* @author codermy
* @createTime 2020/6/15
*/
public interface Cashier {
public Restaurant getFood();
}
然后给每一个菜品新建一个工厂类
EggCooker
/**
* @author codermy
* @createTime 2020/6/15
*/
public class EggCooker implements Cashier {
@Override
public Restaurant getFood() {
return new Egg();
}
}
MeetCooker
/**
* @author codermy
* @createTime 2020/6/15
*/
public class MeetCooker implements Cashier{
@Override
public Restaurant getFood() {
return new Meet();
}
}
然后顾客点单只需要在收银台,餐厅的系统会自动将信息传递给相应的厨师,对应的厨师就能在餐馆中把菜做好
/**
* @author codermy
* @createTime 2020/6/15
* 消费者
*/
public class Customer {
public static void main(String[] args) {
Cashier order = new EggCooker();
Restaurant food = order.getFood();
food.cook();
}
}
输出结果
鸡蛋羹做好了
工厂方法模式解决了简单工厂模式不符合的开闭原则,当添加一个菜品时,只需要再雇佣一个厨师就行(从现实角度看,老板有点亏哦)。但是这也增加了系统的复杂度(菜越多,厨师就越多,这哪家餐馆顶的住)
抽象工厂模式
这个模式解决了每个工厂只能创建一类产品(工厂方法模式)的问题
这里用餐馆的例子不太形象,不是很容易理解,强行举例可能会和上面的方法弄混,我自己绕了好一会,所以我们换一个例子。
现在我们人手不离手机,我们假设手机有如下几个功能
//手机产品接口
public interface IphoneProduct {
void callup();//打电话
void sendSms();//发短信
}
每个人家里又都有路由器,路由器有如下功能
//路由器产品接口
public interface IRouterProduct {
void openwifi();//开启wifi
void setting();//设置wifi
}
然后现在有一个抽象产品工厂,是来生产这两样产品的,假设生产手机和路由器的方法是一样的,只是需要加上厂商信息
//抽象产品工厂
public interface IProductFactory {
//生产手机
IphoneProduct iphoneProduct();
//生产路由器
IRouterProduct iRouterProduct();
}
现在有两家厂商,小米和华为工厂,可以生产手机和路由器,他们两家厂商分别由两条产业线来做手机和路由器
//小米手机
public class XiaomiPhone implements IphoneProduct{
@Override
public void callup() {
System.out.println("用小米手机打电话");
}
@Override
public void sendSms() {
System.out.println("用小米手机发短信");
}
}
//小米路由器
public class XiaomiRouter implements IRouterProduct {
@Override
public void openwifi() {
System.out.println("打开小米wifi");
}
@Override
public void setting() {
System.out.println("设置小米wifi");
}
}
//小米厂商
public class XiaomiFactory implements IProductFactory {
@Override
public IphoneProduct iphoneProduct() {
return new XiaomiPhone();
}
@Override
public IRouterProduct iRouterProduct() {
return new XiaomiRouter();
}
}
//华为手机
public class HuaweiPhone implements IphoneProduct {
@Override
public void callup() {
System.out.println("用华为手机打电话");
}
@Override
public void sendSms() {
System.out.println("用华为手机发短信");
}
}
//华为路由器
public class HuaweiRouter implements IRouterProduct {
@Override
public void openwifi() {
System.out.println("打开华为wifi");
}
@Override
public void setting() {
System.out.println("设置华为wifi");
}
}
//华为工厂
public class HuaweiFactory implements IProductFactory {
@Override
public IphoneProduct iphoneProduct() {
return new HuaweiPhone();
}
@Override
public IRouterProduct iRouterProduct() {
return new HuaweiRouter();
}
}
消费者类
//消费者/测试类
public class Customer {
public static void main(String[] args) {
System.out.println("==============小米产品=================");
XiaomiFactory xiaomiFactory = new XiaomiFactory();//新建一个小米工厂
IphoneProduct xiaomiiphoneProduct = xiaomiFactory.iphoneProduct();//小米工厂开始生产小米手机
xiaomiiphoneProduct.callup();//测试小米手机打电话功能
IRouterProduct xiaomiiRouterProduct = xiaomiFactory.iRouterProduct();//小米工厂开始生产小米路由器
xiaomiiRouterProduct.openwifi();//测试小米路由器打开wifi功能
System.out.println("==============华为产品=================");
HuaweiFactory huaweiFactory = new HuaweiFactory();
IphoneProduct huaweiiphoneProduct1 = huaweiFactory.iphoneProduct();
huaweiiphoneProduct1.callup();
IRouterProduct huaweiiRouterProduct = huaweiFactory.iRouterProduct();
huaweiiRouterProduct.openwifi();
}
}
输出
==============小米产品=================
用小米手机打电话
打开小米wifi
==============华为产品=================
用华为手机打电话
打开华为wifi
抽象工厂模式相较于以上两种模式难以理解一些。这里提供另一种写法比较好理解,来自Guide哥的博客(以下所有内容)
不知道大家玩过穿越火线或者吃鸡这类游戏了吗,游戏中存在各种枪。我们假设现在存在AK、M4A1两类枪,每一种枪对应一种子弹。我们现在这样考虑生产AK的工厂可以顺便生产AK使用的子弹,生产M4A1的工厂可以顺便生产M4A1使用的子弹。(AK工厂生产AK系列产品包括子弹啊,AK枪的类型啊这些,M4A1工厂同理)
————————————————
(1)创建相关接口:
枪
public interface Gun {
public void shooting();
}
子弹
public interface Bullet {
public void load();
}
(2)创建接口对应实现类:
AK类
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
M4A1类
public class M4A1 implements Gun {
@Override
public void shooting() {
System.out.println("shooting with M4A1");
}
}
AK子弹类
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
M4A1子弹类
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
(3)创建工厂接口
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
(4)创建具体工厂
生产AK和AK子弹的工厂
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
生产M4A1和M4A1子弹的工厂
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
(5)测试
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
输出结果:
Load bullets with AK
shooting with AK
java23种设计模式——三、工厂模式的更多相关文章
- Spring 实现两种设计模式:工厂模式和单态模式(单例模式)
本文摘自:李刚 著 <轻量级 Java EE企业应用实战 Struts2+Spring+hibernate整合开发> 在Spring 中大量使用的以下两种设计模式:工厂模式和单态模式. 工 ...
- java23种设计模式之八: 工厂方法模式
定义: 定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中.这满足创建型模式中所要求的“创建与使用相分离”的特点. 我们把被创建的对象称为“产品”,把创建产品的对象称为“工 ...
- 24种设计模式--抽象工厂模式【Abstract Factory Pattern】
女娲造人,人是造出来了,世界是热闹了,可是低头一看,都是清一色的类型,缺少关爱.仇恨.喜怒哀乐等情绪,人类的生命太平淡了,女娲一想,猛然一拍脑袋,忘记给人类定义性别了,那怎么办?抹掉重来,然后就把人类 ...
- java23种设计模式之四:建造者模式
在软件开发过程中有时需要创建一个复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成.例如:在新招收一个员工时,对个人信息对象的创建,在不同的阶段,需要个人信息的内容也不一样,姓名.性别.年龄 ...
- Java--23种设计模式之decorator模式
装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性.动态给一个对象增加功能,这些功能可以再动态的撤消.增加由一些基本功能的排列组合而产生的非常大量的 ...
- java23种设计模式之一: 策略模式
由于最近在研究学习设计模式,我会用自己的理解方式来表述对设计模式的学习和认识,通过最常用.好记的案例来记住和使用设计模式,希望对设计代码方面有所提高和改进. 一.应用背景 在软件开发中常常遇到 ...
- java23种设计模式之一: 代理模式(动态代理)
在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...
- java23种设计模式之: 策略模式,观察者模式
策略模式 --老司机开车,但是他今天想到路虎,明天想开奔驰...针对他不同的需求,来产生不同的应对策略 策略类是一个接口,定义了一个大概的方法,而实现具体的策略则是由实现类完成的,这样的目的是 ...
- java23种设计模式之五:代理模式
一.代理模式介绍 代理模式的定义:就是为一个接品(对象)提供一个代理的对象,并由这个代理对象控制对原对象的访问流程 其中代理又分为:静态代理和动态代理 静态代理:指的是自己要写一个代理类,或者用工具生 ...
随机推荐
- Python定义一个函数
Python函数:实现某种功能的代码段 定义一个函数需要遵循的规则: 1.使用 def 关键字 函数名和( ),括号内可以有形参 匿名函数使用 lambda 关键字定义 2.任何传入参数和自变量必须放 ...
- 美团Leaf——全局序列生成器
Leaf的Github地址: https://github.com/Meituan-Dianping/Leaf Leaf美团技术团队博客地址: https://tech.meituan.com/201 ...
- Python os.remove() 方法
概述 os.remove() 方法用于删除指定路径的文件.如果指定的路径是一个目录,将抛出OSError.高佣联盟 www.cgewang.com 在Unix, Windows中有效 语法 remov ...
- Hadoop学习之TextInputFormat分片逻辑探究
期望 顺着上一篇文章<Hadoop学习之第一个MapReduce程序>中遗留的分片疑惑,探究TextInputFormat的分片逻辑. 第一步 上Apache官网下载实验所使用的Hadoo ...
- linux的文件处理(匹配 正则表达式 egrep awk sed)和系统、核心数据备份
文件处理 1.处理方式 匹配 正则表达式 egrep awk sed 2.文件中的处理字符 \n 新行符 换行 \t 制表符 tab键 缺省8个空格 \b 退格符 backspace键 退格键 ...
- 数据结构中的树(二叉树、二叉搜索树、AVL树)
数据结构动图展示网站 树的概念 树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合.它是由n(n>=1)个有限节点组成一个具有 ...
- js 事件对象相关笔记
事件对象 event就是一个事件对象 写到我们的监听函数的括号里面 当形参来看 事件对象只有有了事件才存在,他是系统给我们自动创建的 不需要我们传递参数 事件对象是我们事件的一 ...
- week4:周测错题
4.如何在类外,给对象动态添加绑定方法 import types def qingtianzhu(obj,name): print("请我叫我一柱擎天,简称{},颜色是{}".fo ...
- Properties类的使用 序列化与反序列化
Properties 类表示了一个持久的属性集.Properties 可保存在流中或从流中加载.属性列表中每个键及其对应值都是一个字符串. 特点: 1.Hashtable的子类,map集合中的方法都可 ...
- 文章要保存为TXT文件,其中的图片要怎么办?Python帮你解决
前言 用 python 爬取你喜欢的 CSDN 的原创文章,保存为TXT文件,不仅查看不方便,而且还无法保存文章中的代码和图片. 今天教你制作成 PDF 慢慢看.万一作者的突然把号给删了,也会保存备份 ...