3.3FactoryMethod——工厂方法

news/2024/9/20 11:13:11

意图:

定义一个用于创建对象的接口,让子类决定实例化哪一个类。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

相关文章

Springboot笔记

文章目录[toc]SpringBoot的pom配置SpringBoot的常用注解SpringBoot的启动的三种形式SpringBoot的SpringBootApplicationSpringBoot的静态资源访问SpringBoot的接⼝返回⼯具类SpringBoot的使用RequestBody接收前端jsonSpringBoot的配置Jackson处理字段SpringBoot的热部署SpringB…

spark常用RDD算子 - PairRDD的Action操作countByKey, collectAsMap

countByKey 返回每个key的个数 def countByKey(): Map[K, Long] 以RDD{(1, 2),(2,4),(2,5), (3, 4),(3,5), (3, 6)}为例 rdd.countByKey会返回{(1,1),(2,2),(3,3)} JavaPairRDD<Integer, Integer> rdd javaSparkContext.parallelizePairs(Arrays.asList(new Tuple2&…

Spring与Hibernate、Mybatis整合

在Web项目中一般会把各个web框架结合在一起使用&#xff0c;比如springhibernate&#xff0c;springibatis等&#xff0c;如此以来将其他的框架整合到spring中来&#xff0c;便有些少许的不便&#xff0c;当然spring已经把这种整合变得很简单了。本人结合在项目中使用过的sprin…

学习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整合断路器的使用…

Spark Rdd分区 coalesce()方法和repartition()方法

有两种方法是可以重设Rdd的分区&#xff1a;分别是 coalesce()方法和repartition()。 这两个方法有什么区别&#xff0c;看看源码就知道了&#xff1a;coalesce只能减少分区&#xff0c;而repartition可以减少和增加repartition()方法就是coalesce()方法shuffle为true的情况 有…

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

说理论&#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…

配置开发支持高并发TCP连接的Linux应用程序全攻略

1、修改用户进程可打开文件数限制在Linux平台上&#xff0c;无论编写客户端程序还是服务端程序&#xff0c;在进行高并发TCP连接处理时&#xff0c;最高的并发数量都要受到系统对用户单一进程同时可打开文件数量 的限制(这是因为系统为每个TCP连接都要创建一个socket句柄&#…

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…