3.3FactoryMethod——工厂方法

news/2023/9/27 6:01:46

意图:

定义一个用于创建对象的接口,让子类决定实例化哪一个类。FactoryMethod使一个类的实例化延迟到其子类。

 

其实在抽象工厂模式中,经过改进后的模式就是工厂方法模式,所以不多说了,上UML图。


 

通过工厂方法模式的类图可以看到,工厂方法模式有四个要素:

1.工厂接口。工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品。在实际编程中,有时候也会使用一个抽象类作为与调用者交互的接口,其本质上是一样的。

 

2.工厂实现。在编程中,工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现。

 

3.产品接口。产品接口的主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性。同样,产品接口也可以用抽象类来代替,但要注意最好不要违反里氏替换原则。

 

4.产品实现。实现产品接口的具体类,决定了产品在客户端中的具体行为。

 

前文提到的简单工厂模式跟工厂方法模式极为相似,区别是:简单工厂只有三个要素,他没有工厂接口,并且得到产品的方法一般是静态的。因为没有工厂接口,所以在工厂实现的扩展性方面稍弱,可以算作工厂方法模式的简化版

 

举例说明:

还是举生产产品的例子吧。一个工厂生产A,B两种产品,以后还可能会拓展生产C产品,怎么安排类的设计模式使得以后的拓展或者用户额调用更加方便——工厂方法模式。

//定义工厂方法所创建的对象的接口
#ifndef _PRODUCT_H
#define  _PRODUCT_Hclass Product
{
protected:Product(){}
public:virtual ~Product(){}virtual void function() = 0;
};
#endif//实现Product接口
#ifndef _CONCRETE_PRODUCT_A_H
#define _CONCRETE_PRODUCT_A_H#include "Product.h"
#include <iostream>
using namespace std;class ConcreteProductA : public Product
{
public:ConcreteProductA(){cout<<"创建产品A"<<endl;}virtual ~ConcreteProductA(){cout<<"销毁产品A"<<endl;}virtual void function(){cout<<"这是产品A的功能"<<endl;}};
#endif//实现Product接口
#ifndef _CONCRETE_PRODUCT_B_H
#define _CONCRETE_PRODUCT_B_H#include "Product.h"
#include <iostream>
using namespace std;class ConcreteProductB : public Product
{
public:ConcreteProductB(){cout<<"创建产品B"<<endl;}virtual ~ConcreteProductB(){cout<<"销毁产品B"<<endl;}virtual void function(){cout<<"这是产品B的功能"<<endl;}};
#endif//声明工厂方法,该方法返回一个Product类型的对象
#ifndef _CREATER_H
#define  _CREATER_Hclass Creator
{
public:Creator(){}virtual ~Creator(){}virtual Product *CreateProduct(int type=0) = 0;//参数化工厂方法
};
#endif//重定义工厂方法以返回一个ConcreteProduct实例
#ifndef _CONCRETE_CREATOR_H
#define  _CONCRETE_CREATOR_H#include "ConcreteProductA.h"
#include "ConcreteProductB.h"
#include "Product.h"
class ConcreteCreator : public Creator
{
public:ConcreteCreator(){}virtual ~ConcreteCreator(){}virtual Product *CreateProduct(int type){Product *product;switch(type){case 0:product = new ConcreteProductA();break;case 1:product = new ConcreteProductB();break;default:product = new ConcreteProductA();break;}return product;}};
#endif客户端程序:
#include "Product.h"
#include "ConcreteProductA.h"
#include "ConcreteProductB.h"
#include "Creator.h"
#include "ConcreteCreator.h"int main(int argc, char **argv)
{Creator *c = new ConcreteCreator();Product *p = c->CreateProduct(0);p->function();delete p;delete c;system("pause");return 0;
}

 

当我们的系统需要增加其他新的对象时,我们只需要添加一个具体的产品和它的创建工厂即可,不需要对原工厂进行任何修改,这样很好地符合了“开闭原则”。

 

工厂方法适用场景

1、一个类不知道它所需要的对象的类。在工厂方法模式中,我们不需要具体产品的类名,我们只需要知道创建它的具体工厂即可。

2、一个类通过其子类来指定创建那个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

3、将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定。


转载于:https://www.cnblogs.com/snake-hand/p/3181602.html


https://dhexx.cn/news/show-18421.html

相关文章

学习ASP.NET MVC(五)——我的第一个ASP.NET MVC CURD页面

在上一篇文章中我们已经创建了实体类&#xff0c;在这一篇文章中&#xff0c;我将创建一个新的控制器类——BookController&#xff0c;使用BookController对Books表中的数据进行CURD操作的方法&#xff0c;并使用视图模板在浏览器中显示所查询到的书籍数据信息。 一、添加控制…

SpringCloud学习之路

SpringCloud学习之路1、使用IDEA搭建Eureka服务中心Server端启动1.1、创建和配置注册中心Eureka1.2、使用Eureka案例1.3、负载均衡器Ribbon1.4、负载均衡器Feign1.5、Feign核心源码解读和服务调用方式ribbon和Feign选择2、降级熔断Hystrix实战2.1、SpringCloud整合断路器的使用…

存储引擎-存储结构之二:页

说理论&#xff0c;总是枯燥的&#xff0c;先来段搞笑视频&#xff0c;清清脑 模特兒走秀摔倒集錦&#xff1a;http://947kan.com/video/player-53088-0-0.html 原文地址&#xff1a; http://www.sqlskills.com/BLOGS/PAUL/post/Inside-the-Storage-Engine-Anatomy-of-a-page.a…

Spark RDD中的宽依赖和窄依赖

Spark中RDD的高效与DAG图有着莫大的关系&#xff0c; 在DAG调度中需要对计算过程划分Stage&#xff0c; 而划分的依据就是就是RDD之间的依赖关系。 针对不同的转换函数&#xff0c;RDD之间的依赖关系分为窄依赖&#xff08;narrow dependency&#xff09; 和宽依赖&#xf…

学习java虚拟机

学习java虚拟机1、类加载的五个过程&#xff1a;加载、验证、准备、解析、初始化2、类的加载器的分类2.1、双亲委派机制3、类的加载器的分类4、Java虚拟机栈5、Java本地方法栈6、Java虚拟机栈7、Java堆8、Java方法区9、Java常量池10、Java对象创建步骤11、Java对象的内存结果12…

MySQL学习日记

MySQL学习日记1、笔记1、升序降序2、in的用法3、奇数偶数方法4、不重复查询5、where和and的区别6、函数rank()、dense_rank()、row_number()7、group by原理和理解8、SQL语句中同时出现count()、where、group by 的先后执行顺序9、LIKE 语法10、CONCAT()的用法11、插入语句之va…

阿里云服务器上安装mysql的心路历程(博友们进来看看哦)

在阿里云花了100买了一台云服务器&#xff0c;配置如下&#xff1a; CPU&#xff1a; 1核 内存&#xff1a; 512MB 数据盘&#xff1a; 0G 带宽&#xff1a; 1Mbps 阿里云服务器安装mysql搞得我想吐血&#xff0c;搞了一个多星期&#xff0c;现在才搞好&#xff0c;而且&#x…

MAC电脑之搭建lua开发环境

下载和安装lua&#xff1a;&#xff08;转自这里&#xff09;1. 下载最新版的lua-5.2.0 请点击&#xff0c;然后使用tar -zxvf lua.xxxx 解压 2. 运行“终端”进入解压后的文件夹3.在“终端”输入 make macosx &#xff08;回车&#xff09;4.在“终端”输入 make tes…

深入学习存储过程

深入学习存储过程介绍优点缺点存储过程中的关键语法声明语句结束符&#xff0c;可以自定义。声明存储过程存储过程开始和结束符号变量赋值变量定义创建mysql存储过程、存储函数存储过程体举例说明存储过程的例子调用存储过程存储过程的参数IN 输入参数OUT 输出参数INOUT 输入输…

指针的疑问

1.一个指针变量占用多少个字节的内存空间&#xff1f;占用的空间是否会跟随所指向变量的类型而改变&#xff1f; 在同一种编译器环境下&#xff0c;一个指针变量所占用的内存空间是固定的。比如&#xff0c;在16位编译器环境下&#xff0c;任何一个指针变量都只占用2个字节&…