设计模式:单例模式和工厂模式

引言

本篇文章介绍了多种设计模式,我们不仅仅只需要理解设计模式,还要可以写出类似的代码。

单例模式

单例模式故名思意就是全局只设置一个实例,全局的所有对象都可以访问这个实例。这样子的优点有几个:

我们可以比较方便的管理这一个实例,并且在创建的时候我们也有两个选择,一个是一开始就创建这个对象,这个叫"饿汉模式",一个是当要用的时候再创建,这个叫"懒汉模式"。但是大家注意,这个懒汉模式会有一个比较坑的地方,如果更巧在同一时刻多个线程同时创建了这个对象,那么很可能一下子就出现了多个单例,所以就失效了,那么我们就需要加锁~~~不过对于c++来说不需要,我们代码里面会说明。

我们要创建一个单例需要满足几个条件:私有的构造函数(防止new出新对象),共有的静态方法,私有的静态实例变量(就是和这个实例有关的变量,因为实例既然不可以让别人公开创建,说明这个变量全局也只有一个)。

我们还是用一个例子来引出单例模式的代码,不过我们还是先分析一下这个例子为什么是单例模式。首先我们只有一个购物车,这个购物车

小明去了一家大型商场,拿到了一个购物车,并开始购物。请你设计一个购物车管理器,记录商品添加到购物车的信息(商品名称和购买数量),并在购买结束后打印出商品清单。

首先我们为了禁止new其他的实例,我们先把构造函数放进私有类,然后c++11里面增加了一个新特性就是static函数的调用会按照顺序调用,也就是相当于加了一个锁,所以在c++里面我们不需要单独加锁,并且我们的static也方便外部调用,不需要创建对象,直接访问,并且因为这是一个全局变量,所以我们使用指针的形式进行保存,当然也可以用引用&的形式。

cpp 复制代码
class ShoppingCartManager {
private:
    unordered_map<string, int> cart;
    vector<string> order; // 保持顺序

    // 私有构造函数
    ShoppingCartManager() {}

public:
    // 获取购物车实例
    static ShoppingCartManager* getInstance() {
        static ShoppingCartManager instance;
        return &instance;
    }

    // 添加商品
    void addToCart(const string& itemName, int quantity) {
        if (cart.find(itemName) == cart.end()) {
            order.emplace_back(itemName);
        }
        cart[itemName] += quantity;
    }

    // 查看商品
    void viewCart() const {
        for (const auto& itemName : order) {
            cout << itemName << " " << cart.at(itemName) << endl;
        }
    }
};

我们先得到我们的实例,然后才开始操作

cpp 复制代码
void SingletonPatternTest() {
    string itemName;
    int quantity;

    ShoppingCartManager* cart = ShoppingCartManager::getInstance();

    string line;

    while (getline(cin, line)) {
        if (line.empty()) {
            break;
        }

        stringstream input(line);

        if (input >> itemName >> quantity) {
            cart->addToCart(itemName, quantity);
        }
    }

    cart->viewCart();
}

工厂模式

我们首先要介绍工厂模式,就是if-else之类的,但是这个有一个很大的弊端就是代码一旦扩展,那么这所有的代码都需要被改动,所以扩展性十分的差。那么就要提到我们的工厂模式。我们的工厂分为具体工厂和抽象工厂,具体工厂就是具体干活的,而抽象工厂是一个基类,也就是提供给我们一个访问的接口,我们外人的访问都是抽象的,因为这样就可以避免我们对于具体类的一个操作,完完全全的屏蔽了对于内部的一个访问。

工厂模式有一下的几个角色:

  • 抽象工厂:一个接口,包含一个抽象的工厂方法(用于创建产品对象)。
  • 具体工厂:实现抽象工厂接口,创建具体的产品。
  • 抽象产品:定义产品的接口。
  • 具体产品:实现抽象产品接口,是工厂创建的对象。

我们还是用一个场景带入理解:

小明家有两个工厂,一个用于生产圆形积木,一个用于生产方形积木,请你帮他设计一个积木工厂系统,记录积木生产的信息。

这个是我们的产品区,也就是我们怎么产生产品(利用工厂提供的资源),首先我们提供了一个产品的抽象类,我们之后也是通过这个接口来访问不同的产品。

cpp 复制代码
class Block {
public:
    virtual void produce() = 0;
};

class CircleBlock : public Block {
public:
    void produce() override {
        std::cout << "CircleBlock produced" << std::endl;
    }
};

class SquareBlock : public Block {
public:
    void produce() override {
        std::cout << "SquareBlock produced" << std::endl;
    }
};

这个是工厂区,因为这个比较的简单,所以工厂的作用就是返回每个工厂对应的产品(new出来),而我们对外面提供的就是抽象类。

cpp 复制代码
class BlockFactory {
public:
    virtual Block* createBlock() = 0;
};

class CircleBlockFactory : public BlockFactory {
public:
    virtual Block* createBlock() override {
        return new CircleBlock();
    }
};

class SquareBlockFactory : public BlockFactory {
public:
    virtual Block* createBlock() override {
        return new SquareBlock();
    }
};

最后我们对外面提供一个统一的接口,外面访问的时候需要传递需要制造物品的工厂,对应的数量,所以我们可以看到我们使用的全部都是基类,因为外面传递进来的一定是具体的子类,然后我们在调用的函数也是抽象类里面的,因为最后根据传入的参数会匹配到对应的函数。

cpp 复制代码
class BlockFactorySystem {
private:
    std::vector<Block*> blocks;

public:
    void produceBlock(BlockFactory* factory, int quantity) {
        for (int i = 0; i < quantity; i++) {
            Block* block = factory->createBlock();
            blocks.push_back(block);
            block->produce();
        }
    }

    const std::vector<Block*>& getBlocks() {
        return blocks;
    }

    ~BlockFactorySystem() {
        for (Block* block : blocks) {
            delete block;
        }
    }
};

最后就是怎么使用这个工厂,我们先创建一个大工厂,因为这个是我们访问的入口,然后根据需求传递参数,不过大家要记得我们在一开始只创建了一个大工厂,而我们的小工厂还没有创建,所以在传递的时候要顺便new一个工厂,而产品的产生则不需要我们关心,因为工厂会自己产生。

cpp 复制代码
void FactoryPartternTest() {
    BlockFactorySystem blockFactorySystem;

    int productionCount = 0;
    std::cin >> productionCount;

    for (int i = 0; i < productionCount; i++) {
        std::string blockType;
        int quantity;
        std::cin >> blockType >> quantity;

        if (blockType == "Circle") {
            blockFactorySystem.produceBlock(new CircleBlockFactory(), quantity);
        } else if (blockType == "Square") {
            blockFactorySystem.produceBlock(new SquareBlockFactory(), quantity);
        }
    }
    return;
}

总结

本篇文章就到这里结束了!!!设计模式不仅仅在我们构建架构的时候会有帮助,其实更多的时候是在读代码,可以帮我们省很多的时间帮我们搞清楚架构,这个很重要。所以希望可以帮助大家理解~~~

相关推荐
Henry Zhu1233 小时前
C++ 动态多态详解
c++
此生决int3 小时前
深入理解C++系列(06)——模版初阶与STL
开发语言·c++
c238564 小时前
《枚举算法 “翻译官”:用 enum class 给 “游游的礼盒” 算分》
c语言·c++·算法
noipp4 小时前
推荐题目:洛谷 P5843 [SCOI2012] Blinker 的噩梦
c语言·数据结构·c++·算法·游戏·洛谷·luogu
鱼子星_4 小时前
《算 · 法》题目解析篇(1):最近公共祖先问题,线段树,最长回文子序列
c++·算法·动态规划·递归
小白说大模型6 小时前
Python 工程化设计模式:AI 项目中的异步流水线与策略模式实战
人工智能·python·设计模式
计算机内卷的N天6 小时前
CMake与Visual Studio的使用
c++·ide·visual studio
汉克老师6 小时前
GESP2026年3月认证C++七级( 第三部分编程题(1、物流网络))精讲
c++·最短路·gesp7级
鱼子星_6 小时前
【C++】深入剖析list:list及其双向迭代器实现
开发语言·数据结构·c++·笔记·stl·list