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

ops/2024/11/19 4:28:45/

本文主要是记录学习设计模式当中的工厂方法和抽象工厂时碰到的疑惑和对答案的探讨

刚接触时的工厂方法模式和抽象工厂模式

工厂方法模式

类图

代码

java">
//工厂public interface TVFactory {TV produce();
}public class TclTVFactory implements TVFactory{@Overridepublic TV produce() {System.out.println("TCL工厂生产了一台TCL电视");return new TclTV();}
}//产品public interface TV {void play();
}public class TclTV implements TV{@Overridepublic void play() {System.out.println("你好,我是TCL电视");}
}
java">public class Client {public static void main(String[] args) {TVFactory factory;TV tv;factory = new TclTVFactory();tv = factory.produce();tv.play();}
}

运行结果

TCL工厂生产了一台TCL电视
你好,我是TCL电视

根据上面的方法,当需要增加生产一个品牌的产品时,例如生产hisense电视,只需要再增加一个工厂类HisenseTVFactory实现TVFactory接口,和一个产品类HisenseTV实现TV接口即可,无需改动源代码,符合开闭原则。

抽象工厂模式

类图

代码

java">public interface Factory {TV produceTV();Fridge produceFridge();}public class TCLFactory implements Factory{@Overridepublic TV produceTV() {System.out.println("生产了TCL电视");return new TclTV();}@Overridepublic Fridge produceFridge() {System.out.println("生产了TCL冰箱");return new TclFridge();}
}public class HisenseFactory implements Factory{@Overridepublic TV produceTV() {System.out.println("生产了海信电视");return new HisenseTV();}@Overridepublic Fridge produceFridge() {System.out.println("生产了海信冰箱");return new HisenseFridge();}
}
java">public interface TV {void play();
}public class TclTV implements TV{@Overridepublic void play() {System.out.println("我是TCL电视");}
}public class HisenseTV implements TV{@Overridepublic void play() {System.out.println("我是海信电视");}
}public interface Fridge {void cooling();
}public class TclFridge implements Fridge{@Overridepublic void cooling() {System.out.println("我是TCL冰箱");}
}public class HisenseFridge implements Fridge{@Overridepublic void cooling() {System.out.println("我是海信冰箱");}
}
java">public class Client {public static void main(String[] args) {Factory factory;TV tv;Fridge fridge;factory = new HisenseFactory();tv = factory.produceTV();tv.play();fridge = factory.produceFridge();fridge.cooling();}
}

运行结果

生产了海信电视
我是海信电视
生产了海信冰箱
我是海信冰箱

由以上可知,抽象工厂模式增加产品族的时候是不需要修改原来的代码的符合开闭原则,但是增加产品等级结构,那就不适用了

学完工厂方法模式和抽象工厂模式后的问题

相信许多人和我一样,在学完上述两个模式后,再看到模式的分类,就会产生一个疑问

模式的分类就是工厂方法模式属于类模式,抽象工厂模式属于对象模式

看到这里我云里雾里的,什么是类模式什么是对象模式?好吧,以下是软设教材的概念

看到这里还是不懂,而且我发现用之前的工厂方法和抽象工厂方法的类图去套这条解释,我会发现,要么都是类模式要么都是对象模式,没有什么不同啊(都是增加一个抽象工厂/具体工厂和抽象产品/具体产品,client的调用也是一样的)

由此我开始了漫长的探索之路,直到我看到了这篇解释,突然豁然开朗,为避免歧义,我粘贴原文,有需要的自行复制翻译

The main difference between Abstract Factory and Factory Method is that Abstract Factory is implemented by Composition; but Factory Method is implemented by Inheritance.

Yes, you read that correctly: the main difference between these two patterns is the old composition vs inheritance debate.

UML diagrams can be found in the (GoF) book. I want to provide code examples, because I think combining the examples from the top two answers in this thread will give a better demonstration than either answer alone. Additionally, I have used terminology from the book in class and method names.

Abstract Factory

  1. The most important point to grasp here is that the abstract factory is injected into the client. This is why we say that Abstract Factory is implemented by Composition. Often, a dependency injection framework would perform that task; but a framework is not required for DI.
  2. The second critical point is that the concrete factories here are not Factory Method implementations! Example code for Factory Method is shown further below.
  3. And finally, the third point to note is the relationship between the products: in this case the outbound and reply queues. One concrete factory produces Azure queues, the other MSMQ. The GoF refers to this product relationship as a "family" and it's important to be aware that family in this case does not mean class hierarchy.
java">public class Client {private final AbstractFactory_MessageQueue factory;public Client(AbstractFactory_MessageQueue factory) {// The factory creates message queues either for Azure or MSMQ.// The client does not know which technology is used.this.factory = factory;}public void sendMessage() {//The client doesn't know whether the OutboundQueue is Azure or MSMQ.OutboundQueue out = factory.createProductA();out.sendMessage("Hello Abstract Factory!");}public String receiveMessage() {//The client doesn't know whether the ReplyQueue is Azure or MSMQ.ReplyQueue in = factory.createProductB();return in.receiveMessage();}
}public interface AbstractFactory_MessageQueue {OutboundQueue createProductA();ReplyQueue createProductB();
}public class ConcreteFactory_Azure implements AbstractFactory_MessageQueue {@Overridepublic OutboundQueue createProductA() {return new AzureMessageQueue();}@Overridepublic ReplyQueue createProductB() {return new AzureResponseMessageQueue();}
}public class ConcreteFactory_Msmq implements AbstractFactory_MessageQueue {@Overridepublic OutboundQueue createProductA() {return new MsmqMessageQueue();}@Overridepublic ReplyQueue createProductB() {return new MsmqResponseMessageQueue();}
}

Factory Method

  1. The most important point to grasp here is that the is the client. In other words, the client is a subclass whose parent defines the . This is why we say that Factory Method is implemented by Inheritance.ConcreteCreatorfactoryMethod()
  2. The second critical point is to remember that the Factory Method Pattern is nothing more than a specialization of the Template Method Pattern. The two patterns share an identical structure. They only differ in purpose. Factory Method is creational (it builds something) whereas Template Method is behavioral (it computes something).
  3. And finally, the third point to note is that the (parent) class invokes its own . If we remove from the parent class, leaving only a single method behind, it is no longer the Factory Method pattern. In other words, Factory Method cannot be implemented with less than two methods in the parent class; and one must invoke the other.CreatorfactoryMethod()anOperation()
java">public abstract class Creator {public void anOperation() {Product p = factoryMethod();p.whatever();}protected abstract Product factoryMethod();
}public class ConcreteCreator extends Creator {@Overrideprotected Product factoryMethod() {return new ConcreteProduct();}
}

再配合软设教材的两个类图,这才发现两者的区别

工厂方法模式

抽象工厂模式

好了,就说到这里了,剩下的就靠大家自己体会领悟了,再见^_^

附录:

参考书籍

《软件设计师教程》

相关论坛

java">https://stackoverflow.com/questions/46041363/why-is-factory-method-a-class-pattern-while-an-abstract-factory-an-object-patte
https://stackoverflow.com/questions/5739611/what-are-the-differences-between-abstract-factory-and-factory-design-patterns#
https://blog.csdn.net/lovelion/article/details/9319481


http://www.ppmy.cn/ops/134861.html

相关文章

MATLAB和Python及R瑞利散射

MATLAB片段 在MATLAB中处理瑞利散射(Rayleigh scattering)通常涉及到理解和应用瑞利散射公式。瑞利散射描述了当光波与比其波长小得多的粒子(如气体分子或小颗粒)发生相互作用时,散射光的强度与波长的关系。 瑞利散射…

小程序如何完成订阅

小程序如何完成订阅 参考相关文档实践问题处理授权弹窗不再触发引导用户重新授权 参考相关文档 微信小程序实现订阅消息推送的实现步骤 发送订阅消息 小程序订阅消息(用户通过弹窗订阅)开发指南 实践 我们需要先选这一个模板,具体流程参考…

Java基础-集合

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 前言 一、Java集合框架概述 二、Collection接口及其实现 2.1 Collection接口 2.2 List接口及其实现 …

Android12的ANR解析

0. 参考: ANR分析 深入理解 Android ANR 触发原理以及信息收集过程 1.ANR的触发分类: ANR分为4类: InputDispatchTimeout:输入事件分发超时5s,包括按键和触摸事件。BroadcastTimeout:比如前台广播在10s内未执行完成&#xff0…

【Linux学习】【Ubuntu入门】1-4 ubuntu终端操作与shell命令1

1.使用快捷键CtrlAltT打开命令终端,或者单击右键点击… 2.常用shell命令 目录信息查看命令:ls ls -a:显示目录所有文件及文件夹,包括隐藏文件,比如以.开头的 ls -l:显示文件的详细信息 ls -al&#xff1…

第8章利用CSS制作导航菜单

8.1 水平顶部导航栏 水平菜单导航栏是应用范围最广的网站导航设计,一般位于页面顶部。它适用性强,几乎适用于所有类型的网站,且设计难度低。若导航过于普通,无法承载复杂信息结构,在内容模块较多时,则需结…

vs2022搭建opencv开发环境

1 下载OpenCV库 https://opencv.org/ 下载对应版本然后进行安装 将bin目录添加到系统环境变量opencv\build\x64\vc16\bin 复制该路径 打开高级设置添加环境变量 vs2022新建一个空项目 修改属性添加头文件路径和库路径 修改链接器,将OpenCV中lib库里的o…

后端一次性返回数据,前端分页

vue 结合elementUI 分页组件&#xff0c;后端一次性返回数据&#xff0c;前端做分页 1.template中 <el-paginationsize-change"handleSizeChange":page-sizes"[10, 20, 50, 100]"style"float:right"current-change"currentChangeHandle…