工厂方法模式(Factory Method)

news2024/12/27 10:47:16

别名

虚拟构造函数(Virtual Constructor)。

定义

工厂方法是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。

前言

1. 问题

假设你正在开发一款物流管理应用。最初版本只能处理卡车运输,因此大部分代码都在位于名为“卡车”的类中。

一段时间后,这款应用变得极受欢迎。你每天都能收到十几次来自海运公司的请求,希望应用能够支持海上物流功能。

这可是个好消息。但是代码问题该如何处理呢?目前,大部分代码都与 卡车 类相关。在程序中添加 轮船 类需要修改全部代码。更糟糕的是,如果你以后需要在程序中支持另外一种运输方式,很可能需要再次对这些代码进行大幅修改。

最后,你将不得不编写繁复的代码,根据不同的运输对象类,在应用中进行不同的处理。

2. 解决方案

工厂方法模式建议使用特殊的工厂方法代替对于对象构造函数的直接调用(即使用 new 运算符)。不用担心,对象仍将通过 new 运算符创建,只是该运算符改在工厂方法中调用罢了。工厂方法返回的对象通常被称作“产品”。

乍看之下,这种更改可能毫无意义:我们只是改变了程序中调用构造函数的位置而已。但是,仔细想一下,现在你可以在子类中重写工厂方法,从而改变其创建产品的类型。

但有一点需要注意:仅当这些产品具有共同的基类或者接口时,子类才能返回不同类型的产品,同时基类中的工厂方法还应将其返回类型声明为这一共有接口。

 

举例来说, 卡车(Truck)和 轮船(Ship)类都必须实现运输(Transport)接口, 该接口声明了一个交付(deliver)的方法。 每个类都将以不同的方式实现该方法:卡车走陆路交付货物,轮船走海路交付货物。

陆路运输(RoadLogistics)类中的工厂方法返回卡车对象,而海路运输(SeaLogistics)类则返回轮船对象。

 结构

  1. 产品(Product)将会对接口进行声明。对于所有由创建者及其子类构建的对象,这些接口都是通用的。
  2. 具体产品(Concrete Products)是产品接口的不同实现。
  3. 创建者(Creator)类声明返回产品对象的工厂方法。该方法的返回对象类型必须与产品接口相匹配。 你可以将工厂方法声明为抽象方法,强制要求每个子类以不同方式实现该方法。或者,你也可以在基础工厂方法中返回默认产品类型。注意,尽管它的名字是创建者,但他最主要的职责并不是创建产品。一般来说,创建者类包含一些与产品相关的核心业务逻辑。工厂方法将这些逻辑处理从具体产品类中分离出来。打个比方,大型软件开发公司拥有程序员培训部门。但是,这些公司的主要工作还是编写代码,而非生产程序员。
  4. 具体创建者(Concrete Creators) 将会重写基础工厂方法,使其返回不同类型的产品。注意,并不一定每次调用工厂方法都会创建新的实例。工厂
    方法也可以返回缓存、对象池或其他来源的已有对象。

优点:

  • 你可以避免创建者和具体产品之间的紧密耦合。
  • 单一职责原则。你可以将产品创建代码放在程序的单一位置,从而使得代码更容易维护。
  • 开闭原则。无需更改现有客户端代码,你就可以在程序中引入新的产品类型。

缺点: 

应用工厂方法模式需要引入许多新的子类,代码可能会因此变得更复杂。最好的情况是将该模式引入创建者类的现有层次结构中。

与其他模式的关系

  • 在许多设计工作的初期都会使用工厂方法(较为简单,而且可以更方便地通过子类进行定制),随后演化为使用抽象工厂原型生成器(更灵活但更加复杂)。
  • 抽象工厂模式通常基于一组工厂方法,但你也可以使用原型模式来生成这些类的方法。
  • 你可以同时使用工厂方法迭代器来让子类集合返回不同类型的迭代器,并使得迭代器与集合相匹配。
  • 原型并不基于继承,因此没有继承的缺点。另一方面,原型需要对被复制对象进行复杂的初始化。 工厂方法基于继承,但是它不需要初始化步骤。
  • 工厂方法模板方法的一种特殊形式。同时,工厂方法可以作为一个大型模板方法中的一个步骤。

实例

Create.hpp

#ifndef B64F5D8C_EC1C_4008_B7FB_B49753A469CC
#define B64F5D8C_EC1C_4008_B7FB_B49753A469CC
#include <memory>
#include <string>
#include "Product.hpp"
using namespace std;


class Factory{
    public:
        virtual std::shared_ptr<Movie> get_movie() = 0;
};
#endif /* B64F5D8C_EC1C_4008_B7FB_B49753A469CC */

ConcreteCreator.hpp

/*
 * @Author: zhaozhiqing1 1652918084@qq.com
 * @Date: 2023-06-24 21:28:50
 * @LastEditors: zhaozhiqing1 1652918084@qq.com
 * @LastEditTime: 2023-06-24 21:31:08
 * @FilePath: /cpp/ConcreteCreator.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#ifndef E8170FEB_50F2_42F6_B7D3_C4BB75737FF0
#define E8170FEB_50F2_42F6_B7D3_C4BB75737FF0
#include <memory>
#include "Create.hpp"
#include "ConcreteProduct.hpp"

class ConcreteProduct : public Factory{
    public:
        shared_ptr<Movie> get_movie(){
            return make_shared<ChineseMoive>();
        }
};
class JapaneseProduct : public Factory{
    shared_ptr<Movie> get_movie(){
        return make_shared<JapaneseMoive>();
    }
};
class KoreanProduct : public Factory{
    shared_ptr<Movie> get_movie(){
        return make_shared<KoreanMoive>();
    }
};

#endif /* E8170FEB_50F2_42F6_B7D3_C4BB75737FF0 */

Product.hpp 

#ifndef EBF4DEFE_3878_49A1_98EB_6498310244A0
#define EBF4DEFE_3878_49A1_98EB_6498310244A0
#include <string>
class Movie{
    public:
        virtual std::string get_a_movie() = 0;
};

#endif /* EBF4DEFE_3878_49A1_98EB_6498310244A0 */

ConcreteProduct.hpp

#ifndef B3B4FD2D_E18D_4FC2_84E6_3C963640CE2B
#define B3B4FD2D_E18D_4FC2_84E6_3C963640CE2B

#include "iostream"
#include "string"
#include "Product.hpp"
using namespace std;
class ChineseMoive : public Movie{
    public:
        string get_a_movie(){
            return "让子弹飞";
        }
};

class JapaneseMovie : public Movie{
    string get_a_movie(){
        return "千与千寻";
    }
};

class KoreanMovie : public Movie{
    string get_a_movie() {
        return "黑暗荣耀";
    };
};

#endif /* B3B4FD2D_E18D_4FC2_84E6_3C963640CE2B */

main.cpp

 

#include "ConcreteCreator.hpp"
using namespace std;
int main(int argc, char const *argv[])
{
    shared_ptr<Factory> factory;
    shared_ptr<Movie> movie;
    string conf = "China";

    if(conf == "China"){
        factory = make_shared<ConcreteProduct>();
    }else if(conf == "Japan"){
        factory = make_shared<JapaneseProduct>();
    }else if(conf == "Korean"){
        factory = make_shared<KoreanProduct>();
    }else{
        cout << "Error: " << conf << endl;
    }
    movie = factory->get_movie();
    cout << "--------------------------------" << endl;
    cout << movie->get_a_movie() << endl;
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/680923.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【85 backtrader-cs因子测试的一些高级技巧-2】使用cython、c语言和c++加速某些函数的计算

在上一篇文章:【85 backtrader-cs因子测试的一些高级技巧】使用numba加速某些函数的计算中,使用了numba改进某些函数,实现加速,在这一篇文章中,尝试接着上一篇文章的主题,继续尝试用cython,c语言和c++尝试改进decayliear函数的计算速度。 结论: 从图上似乎可以得到下面…

Java程序性能优化技巧

1、慎用异常 在Java软件开发中&#xff0c;经常使用 try-catch 进行错误捕获&#xff0c;但是&#xff0c;try-catch 语句对系统性能而言是非常糟糕的。虽然在一次 try-catch中&#xff0c;无法察觉到它对性能带来的损失&#xff0c;但是&#xff0c;一旦try-catch被应用于循环…

从零开始 verilog 以太网交换机(五)帧合路单元的设计与实现

从零开始 verilog 以太网交换机&#xff08;五&#xff09;帧合路单元的设计与实现 &#x1f508;声明&#xff1a; &#x1f603;博主主页&#xff1a;王_嘻嘻的CSDN主页 &#x1f9e8; 从零开始 verilog 以太网交换机系列专栏&#xff1a;点击这里 &#x1f511;未经作者允许…

07-歌词滚动效果

现在学习的代码工作中不一定会需要&#xff0c;如果有&#xff0c;也已经做成了产品和库&#xff0c; 前端重点是创造&#xff0c;面试官考验你的能力是会提出最刁钻的问题给你的。 项目效果 原生JS效率是最高的&#xff0c;框架只是提高代码的可读性 favico图标添加 两种方…

一个工具类让你彻底解决bean深拷贝

深拷贝是我们在代码开发当中经常需要使用到的&#xff0c;但是市面上的对象拷贝方法&#xff0c;比如spring自带的&#xff0c;或者其他工具类带的对象拷贝&#xff0c;大部分都是浅拷贝&#xff0c;根本无法满足咱们的业务需求&#xff0c;我们就只能对里面的引用对象进行专门…

guacamole 纯web rdp预研:web应用程序部分

文章目录 web rdp预研 web应用程序部分预研目的相关基础Web应用结构&#xff08;框架&#xff09;配置tomcat运行web项目与前端交互原理问题整理Java web基础知识Java web调试预研结论 web rdp预研 web应用程序部分 ⭐️来自很多年前的笔记&#xff0c;只是一个归档&#xff0…

面向对象【成员变量与局部变量、方法声明与作用】

文章目录 成员变量局部变量成员变量与局部变量的区别 方法方法的作用方法的声明 成员变量 Java中的成员变量是指类中声明的变量&#xff0c;也称为实例变量或属性。它们与方法一样属于类的成员&#xff0c;不同之处在于&#xff0c;它们存储在对象(堆)中而不是栈中&#xff0c;…

基于灰色预测模型的负荷预测(matlab程序)

0.代码链接 基于灰色预测模型的负荷预测&#xff08;matlab程序&#xff09;资源-CSDN文库 1.简述 灰色预测是一种对含有不确定因素的系统进行预测的方法。灰色预测通过鉴别系统因素之间发展趋势的相异程度&#xff0c;即进行关联分析&#xff0c;并对原始数据进行生成处理来…

python:并发编程(二十六)

前言 本文将和大家一起探讨python并发编程的实际项目&#xff1a;win图形界面应用&#xff08;篇八&#xff0c;共八篇&#xff09;&#xff0c;系列文章将会从零开始构建项目&#xff0c;并逐渐完善项目&#xff0c;最终将项目打造成适用于高并发场景的应用。 本文为python并…

ADAS(高级驾驶员辅助系统)

什么是 ADAS ADAS —— 高级驾驶员辅助系统&#xff0c;包含一系列硬件和软件组件&#xff0c;自动起到驾驶员的多项作用。目前&#xff0c;常见的车辆 ADAS 功能包括自适应巡航控制、盲点检测、变道检测(车道偏离警告系统)、自动车道跟随和自动紧急制动、泊车。 L0到L2称为AD…

测试用例详解(强,硬,牛)

目录&#xff1a; 测试用例价值与体系黑盒测试方法论-等价类黑盒测试方法论-边界值黑盒测试方法论-因果图黑盒测试方法论-判定表黑盒测试方法论-场景法测试用例基础概念测试用例设计与评审面试测试测试用例设计搜索功能测试用例设计 1.测试用例价值与体系 测试用例概念测试…

【MQTT】| 搭建——在云服务器上搭建MQTT服务器

系列文章目录 【MQTT】| 搭建——在云服务器上搭建MQTT服务 失败了也挺可爱&#xff0c;成功了就超帅。 文章目录 前言1. EMQX简介2. EMQX部署3. EMQX一些操作指令3.1 启动EMQX3.2 停止EMQX3.3 检查EMQX运行状态3.4 卸载EMQX 4. EMQX设置4.1 进入EMQX控制面板 5. EMQX测试5.1…

模型评估 (Model Assessment)

1.模型评估 (Model Assessment) 笔记来源于《白话机器学习的数学》 我们训练好模型后&#xff0c;要对知道这个模型到底好不好&#xff0c;定量描述这个模型好坏就是模型评估 把获取的全部训练数据分成两份&#xff1a;一份用于测试&#xff0c;一份用于训练。然后用前者来评估…

数据库实训报告3000字

数据库实训报告1 一、实习目的 认识实习是本科教学计划中非常重要的实践性教学环节&#xff0c;其目的是使学生了解和掌握电力生产知识、印证、巩固和丰富已学过的计算机专业课程内容&#xff0c;培养学生理论联系实际&#xff0c;提高其在生产实践中调查研究、观察问题、分析问…

银行账户管理系统

1. 目的与要求 1、目的: (1)熟练掌握 C语言的基本知识和技能: (2)掌握面向对象程序设计的基本思想和方法;(3)能够利用所学的面向对象基本知识和技能&#xff0c;解决简单应用的程序设计 2、基本要求:(1)利用面向对象的方法以及 C的编程思想来完成系统的设计;(2)在设计的过程中…

抽象工厂模式(Abstract Factory)

定义 抽象工厂是一种创建型设计模式&#xff0c;它能创建一系列相关的对象&#xff0c;而无需指定其具体类。 前言 1. 问题 假设你正在开发一款家具商店模拟器。你的代码中包括一些类&#xff0c;用于表示&#xff1a; 一系列相关产品&#xff0c;例如椅子&#xff08;Chai…

091基于深度学习的手写汉字数字识别含10多种模型

emo仓库和视频演示找091期&#xff1a; 银色子弹zg的个人空间-银色子弹zg个人主页-哔哩哔哩视频 效果展示图如下&#xff1a; 代码文件展示如下&#xff1a; 运行01数据集文本生成制作.py可以读取图片路径保存再txt文本中&#xff0c; 运行02train.py可以对txt文本中的图片路…

同程数科基于 Apache Doris 构建统一实时数仓,查询提速数十倍!

本文导读&#xff1a; 同程数科是同程集团旗下的旅游产业金融科技服务平台&#xff0c;为上下游企业和个人消费者提供数字金融科技服务。近年来&#xff0c;随着同程数科业务的不断拓展和用户量的增加&#xff0c;高效可靠的一站式数据中心建设已成为必不可少的需求。为帮助业…

团体程序设计天梯赛-练习集L2篇④

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;Hello大家好呀&#xff0c;我是陈童学&#xff0c;一个与你一样正在慢慢前行的普通人。 &#x1f3c0;个人主页&#xff1a;陈童学哦CSDN &#x1f4a1;所属专栏&#xff1a;PTA &#x1f381;希望各…

WPF 零基础入门笔记(1):WPF静态页面,布局+样式+触发器

文章目录 官方文档往期回顾零基础笔记项目实战&#xff08;已完结&#xff09; WPF项目创建为什么选net core版本 WPF 静态页面WPF 页面布局WPF样式Style样式行内样式行外样式如果是简单样式&#xff0c;可以这么写如果是复杂样式 WPF样式继承WPF触发器单条件触发器多条件触发 …