[大话设计模式C++版] 第8章 雷锋依然在人间 —— 工厂方法模式

2023-10-29

源码可以在这里找到 大话设计模式C++版

模拟大学生学雷锋

//main.cpp
class LeiFeng {
public:
    void Sweep() {
        cout << "扫地" << endl;
    }
    void Wash() {
        cout << "洗衣" << endl;
    }
    void BuyRice() {
        cout << "买米" << endl;
    }
};

class Undergraduate : public LeiFeng {};

int main(int argc, char *argv[])
{
    //一个大学生完成买米,扫地,洗衣
    LeiFeng* xueleifeng = new Undergraduate();
    xueleifeng->BuyRice();
    xueleifeng->Sweep();
    xueleifeng->Wash();
    
    //三个大学生完成买米,扫地,洗衣
    LeiFeng* student1 = new Undergraduate();
    student1->BuyRice();
    LeiFeng* student2 = new Undergraduate();
    student2->Sweep();
    LeiFeng* student3 = new Undergraduate();
    student3->Wash();

    return 0;
}

老人不关心来的人是谁,只需要知道是志愿者学雷锋就行

简单工厂生产雷锋

#include <iostream>

using namespace std;

class LeiFeng {
public:
    void Sweep() {
        cout << "扫地" << endl;
    }
    void Wash() {
        cout << "洗衣" << endl;
    }
    void BuyRice() {
        cout << "买米" << endl;
    }
};

class Undergraduate : public LeiFeng {};

class Volunteer : public LeiFeng {};

enum LeiFengType {
    UNDERGRADUATE = 0,
    VOLUNTEER
};

class SimpleFactory {
public:
    static LeiFeng* CreateLeiFeng(LeiFengType type) {
        LeiFeng* ret = nullptr;
        switch (int(type)) {
        case 0:
            ret = new Undergraduate();
            break;
        case 1:
            ret = new Volunteer();
            break;
        default:
            break;
        }
        return ret;
    }
};

int main(int argc, char *argv[])
{
    //如果要将下面三个大学生换成志愿者,需要修改三处
    LeiFeng* studentA = SimpleFactory::CreateLeiFeng(UNDERGRADUATE);
    studentA->BuyRice();
    LeiFeng* studentB = SimpleFactory::CreateLeiFeng(UNDERGRADUATE);
    studentB->Sweep();
    LeiFeng* studentC = SimpleFactory::CreateLeiFeng(UNDERGRADUATE);
    studentC->Wash();

    return 0;
}

工厂方法生产雷锋

#include <iostream>

using namespace std;

class LeiFeng {
public:
    void Sweep() {
        cout << "扫地" << endl;
    }
    void Wash() {
        cout << "洗衣" << endl;
    }
    void BuyRice() {
        cout << "买米" << endl;
    }
};

class Undergraduate : public LeiFeng {};

class Volunteer : public LeiFeng {};

class IFactory {
public:
    virtual LeiFeng* CreateLeiFeng() = 0;
    virtual ~IFactory() {}
};

class UndergraduateFactory : public IFactory {
public:
    virtual LeiFeng* CreateLeiFeng() override {
        return new Undergraduate();
    }
};

class VolunteerFactory : public IFactory {
public:
    virtual LeiFeng* CreateLeiFeng() override {
        return new Volunteer();
    }
};

int main(int argc, char *argv[])
{
    //如果要将下面三个大学生换成志愿者,只需要换掉工厂就行
    IFactory* factory = new UndergraduateFactory();
    LeiFeng* studentA = factory->CreateLeiFeng();
    LeiFeng* studentB = factory->CreateLeiFeng();
    LeiFeng* studentC = factory->CreateLeiFeng();

    studentA->BuyRice();
    studentB->Sweep();
    studentC->Wash();

    return 0;
}

小结

简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。

简单工厂模式下如果要增加一个新的功能,需要增加功能类文件,以及在简单工厂中增加相应的 case 条件,简单工厂违背了 开放-封闭原则

工厂方法模式新加功能需要新加功能类文件,并且需要一个增加相应的工厂类,继承与一个抽象工厂。工厂方法模式没有违背 开放-封闭原则

Factory Method工厂方法模式 [李建忠C++笔记]

  • 通过“对象创建”模式绕开 new ,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。
  • 典型模式
    • Factory Method
    • Abstract Factory
    • Prototype
    • Builder

动机(Motivation)

  • 在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。
  • 如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“具体对象创建工作”的紧耦合?
//Splitter.cpp
//抽象分割器
class ISplitter {
public:
	virtual void split() = 0;
	virtual ~ISplitter() {}
};

//具体分割器
class BinarySplitter : public ISplitter {};
class TxtSplitter : public ISplitter {};
class PictureSplitter : public ISplitter {};
class VideoSplitter : public ISplitter {};

//工厂基类
class SplitterFactory {
public:
	virtual ISplitter* CreateSplitter() = 0;
	virtual ~SplitterFactory();
};

//具体工厂
class BinarySplitterFactory : public SplitterFactory {
public:
	virtual ISplitter* CreateSplitter() {
		return new BinarySplitter();
	}
};
class TxtSplitterFactory : public SplitterFactory {
public:
	virtual ISplitter* CreateSplitter() {
		return new TxtSplitter();
	}
};
class PictureSplitterFactory : public SplitterFactory {
public:
	virtual ISplitter* CreateSplitter() {
		return new PictureSplitter();
	}
};
class VideoSplitterFactory : public SplitterFactory {
public:
	virtual ISplitter* CreateSplitter() {
		return new VideoSplitter();
	}
};
//MainForm.cpp
class MainForm : public Form
{
	SplitterFactory* factory;  //工厂
public:
	MainForm(SplitterFactory* factory) {
		this->factory = factory;
	}
	
	void Button1_click() {
		//面向接口编程,对象要声明成抽象基类
		ISplitter* splitter = 
			factory->CreateSplitter();  //多态New
		splitter->split();
	}
};

模式定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。——《设计模式》GoF

在这里插入图片描述

要点总结

  • Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱。
  • Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到了子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
  • Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[大话设计模式C++版] 第8章 雷锋依然在人间 —— 工厂方法模式 的相关文章

  • 如何在MVVM中管理多个窗口

    我知道有几个与此类似的问题 但我还没有找到明确的答案 我正在尝试深入研究 MVVM 并尽可能保持纯粹 但不确定如何在坚持模式的同时启动 关闭窗口 我最初的想法是向 ViewModel 发送数据绑定命令 触发代码来启动一个新视图 然后通过 X
  • C# 和 Javascript SHA256 哈希的代码示例

    我有一个在服务器端运行的 C 算法 它对 Base64 编码的字符串进行哈希处理 byte salt Convert FromBase64String serverSalt Step 1 SHA256Managed sha256 new S
  • 获取按下的按钮的返回值

    我有一个在特定事件中弹出的表单 它从数组中提取按钮并将标签值设置为特定值 因此 如果您要按下或单击此按钮 该函数应返回标签值 我怎样才能做到这一点 我如何知道点击了哪个按钮 此时代码返回 DialogResult 但我想从函数返回 Tag
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • 使闭包捕获的变量变得易失性

    闭包捕获的变量如何与不同线程交互 在下面的示例代码中 我想将totalEvents 声明为易失性的 但C 不允许这样做 是的 我知道这是错误的代码 这只是一个例子 private void WaitFor10Events volatile
  • 为什么#pragma optimize("", off)

    我正在审查一个 C MFC 项目 在某些文件的开头有这样一行 pragma optimize off 我知道这会关闭所有以下功能的优化 但这样做的动机通常是什么 我专门使用它来在一组特定代码中获得更好的调试信息 并在优化的情况下编译应用程序
  • 如果使用 SingleOrDefault() 并在数字列表中搜索不在列表中的数字,如何返回 null?

    使用查询正数列表时SingleOrDefault 当在列表中找不到数字时 如何返回 null 或像 1 这样的自定义值 而不是类型的默认值 在本例中为 0 你可以使用 var first theIntegers Cast
  • WPF TabControl,用C#代码更改TabItem的背景颜色

    嗨 我认为这是一个初学者的问题 我搜索了所有相关问题 但所有这些都由 xaml 回答 但是 我需要的是后台代码 我有一个 TabControl 我需要设置其项目的背景颜色 我需要在选择 取消选择和悬停时为项目设置不同的颜色 非常感谢你的帮助
  • 在数据库中搜索时忽略空文本框

    此代码能够搜索数据并将其加载到DataGridView基于搜索表单文本框中提供的值 如果我将任何文本框留空 则不会有搜索结果 因为 SQL 查询是用 AND 组合的 如何在搜索 从 SQL 查询或 C 代码 时忽略空文本框 private
  • 如何衡量两个字符串之间的相似度? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 给定两个字符串text1 and text2 public SOMEUSABLERETURNTYPE Compare string t
  • 如何将单个 char 转换为 int [重复]

    这个问题在这里已经有答案了 我有一串数字 例如 123456789 我需要提取它们中的每一个以在计算中使用它们 我当然可以通过索引访问每个字符 但是如何将其转换为 int 我研究过 atoi 但它需要一个字符串作为参数 因此 我必须将每个字
  • 当操作繁忙时,表单不执行任何操作(冻结)

    我有一个使用 C 的 WinForms 应用程序 我尝试从文件中读取一些数据并将其插入数据表中 当此操作很忙时 我的表单冻结并且无法移动它 有谁知道我该如何解决这个问题 这可能是因为您在 UI 线程上执行了操作 将文件和数据库操作移至另一个
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • C++ fmt 库,仅使用格式说明符格式化单个参数

    使用 C fmt 库 并给定一个裸格式说明符 有没有办法使用它来格式化单个参数 example std string str magic format 2f 1 23 current method template
  • 需要哪个版本的 Visual C++ 运行时库?

    microsoft 的最新 vcredist 2010 版 是否包含以前的版本 2008 SP1 和 2005 SP1 还是我需要安装全部 3 个版本 谢谢 你需要所有这些
  • 如何让Gtk+窗口背景透明?

    我想让 Gtk 窗口的背景透明 以便只有窗口中的小部件可见 我找到了一些教程 http mikehearn wordpress com 2006 03 26 gtk windows with alpha channels https web
  • Validation.ErrorTemplate 的 Wpf 动态资源查找

    在我的 App xaml 中 我定义了一个资源Validation ErrorTemplate 这取决于动态BorderBrush资源 我打算定义独特的BorderBrush在我拥有的每个窗口以及窗口内的不同块内
  • mysql-connector-c++ - “get_driver_instance”不是“sql::mysql”的成员

    我是 C 的初学者 我认为学习的唯一方法就是接触一些代码 我正在尝试构建一个连接到 mysql 数据库的程序 我在 Linux 上使用 g 没有想法 我运行 make 这是我的错误 hello cpp 38 error get driver
  • 如何在 C++ BOOST 中像图形一样加载 TIFF 图像

    我想要加载一个 tiff 图像 带有带有浮点值的像素的 GEOTIFF 例如 boost C 中的图形 我是 C 的新手 我的目标是使用从源 A 到目标 B 的双向 Dijkstra 来获得更高的性能 Boost GIL load tiif
  • 使用 libcurl 检查 SFTP 站点上是否存在文件

    我使用 C 和 libcurl 进行 SFTP FTPS 传输 在上传文件之前 我需要检查文件是否存在而不实际下载它 如果该文件不存在 我会遇到以下问题 set up curlhandle for the public private ke

随机推荐