当前位置: 首页 > news >正文

设计模式 | 详解常用设计模式(六大设计原则,单例模式,工厂模式,建造者模式,代理模式)

目录

设计模式概述

六大设计原则

从整体理解六大设计原则

单例模式

饿汉模式:

懒汉模式:

 线程安全的懒汉模式

工厂模式

简单工厂模式

抽象工厂模式

建造者模式(Builder Pattern)

代理模式(Proxy Pattern)

总结


设计模式概述

设计模式是前辈们总结出的开发经验,是一系列用来解决特定问题的套路。它不是语法规范,而是帮助我们提升代码复用性、可维护性、可读性、稳健性以及安全性的一套方案。


六大设计原则

  1. 单一职责原则(Single Responsibility Principle)

    • 定义:类的职责应该单一,一个方法只做一件事。这样能使得每次改动的范围最小化。

    • 使用建议:不同的功能应分开到不同的类中。

    • 例子网络聊天中,网络通信和聊天应该分为网络通信类聊天类

    • 📌 总结:每个类应该专注于完成一个功能。

  2. 开闭原则(Open Closed Principle)

    • 定义:对扩展开放,对修改封闭。即程序应该允许扩展,但不应该修改已有的代码。

    • 使用建议:通过扩展已有代码来实现新功能,而不是修改原有功能。

    • 例子:在超时卖货中,通过新增促销价格而不是修改原有商品价格。

    • ⚙️ 总结:改动最小化,扩展能力最强。

  3. 里氏替换原则(Liskov Substitution Principle)

    • 定义:子类应该能够替换父类并且不改变程序的正确性。

    • 使用建议:子类必须完全实现父类的方法,并确保方法的输入参数可被扩展,输出可以缩小。

    • 例子跑步运动员类 - 子类可以是长跑运动员短跑运动员,但是都能执行父类的跑步方法。

    • 👣 总结:继承体系不能破坏,子类需完全实现父类的行为。

  4. 依赖倒置原则(Dependence Inversion Principle)

    • 定义:高层模块不应该依赖低层模块,两者都应该依赖抽象(接口)。

    • 使用建议:模块间通过接口依赖,避免直接依赖具体类。

    • 例子司机类依赖于抽象接口,不依赖于具体车型。

    • 🚗 总结:依赖接口而非具体类,保证灵活性和扩展性。

  5. 迪米特法则(Law of Demeter)

    • 定义:一个对象应该对它的朋友有最少的了解,不应该依赖于朋友的朋友。

    • 使用建议:减少类之间的耦合,限制类之间的交互。

    • 例子老师点名时,老师只交给班长一个名单,班长负责点名,而不是班长直接点名。

    • 🔒 总结:降低类间耦合,减少不必要的依赖。

  6. 接口隔离原则(Interface Segregation Principle)

    • 定义:客户端不应依赖它不需要的接口。

    • 使用建议:接口设计应该精简,避免暴露无用的方法。

    • 例子:修改密码的接口不应包含修改其他用户信息的功能。

    • 🔑 总结:接口简洁,每个接口只应提供相关功能。


从整体理解六大设计原则

  • 单一职责原则:实现类要职责单一。

  • 里氏替换原则:保持继承体系的完整性。

  • 依赖倒置原则:依赖接口编程,避免具体实现依赖。

  • 接口隔离原则:设计接口时要精简。

  • 迪米特法则:降低类之间的耦合。

  • 开闭原则:扩展系统时应对扩展开放,对修改封闭。


单例模式

单例模式确保一个类只有一个实例,并提供全局访问点。适用于需要全局共享数据或配置的场景。

这种方式的优势在于简单且线程安全,但它的缺点是程序启动时就创建了实例,可能会浪费一些内存资源,特别是如果程序从未使用这个单例对象的话。

饿汉模式
  • 程序启动时就创建单一实例,适用于多线程环境,性能高。

    🐯 饿汉模式实现

    #include <iostream>
    //1.饿汉模式
    //--不管用不用,先实例化一个出来再说class singleton {//--构造析构私有化,防止外部创建对象
    private:singleton() {};~singleton() {};
    public:--拷贝构造赋值重载delete,防止拷贝和赋值singleton(const singleton& s) = delete;singleton& operator=(const singleton& s) = delete;// 静态成员函数,用于获取单例实例static singleton& getInstance() {return instance;}//静态成员函数,单例的方法static void Work() { std::cout << "我是单例的方法" << std::endl; };
    private://静态成员变量static singleton instance;
    };// 初始化静态成员变量
    singleton singleton::instance;int main() {// 获取单例实例singleton& sg = singleton::getInstance();sg.Work();return 0;
    }
    
  • 总结

  • 饿汉式单例模式:在程序启动时就创建单例实例,无论是否使用它。这样可以避免多线程问题,确保实例的创建是线程安全的。

  • 私有化构造函数和析构函数:确保外部不能直接创建或销毁实例,保护了单例的唯一性。

  • 删除拷贝构造和赋值运算符:避免单例对象被拷贝或赋值,保证了全局只有一个实例。

  • 懒汉模式
  • 第一次使用时才创建实例,适用于资源消耗较大时。

    懒汉模式实现

    class singleton {//--构造析构私有化,防止外部创建对象
    private:singleton() {};~singleton() {};
    public:--拷贝构造赋值重载delete,防止拷贝和赋值singleton(const singleton& s) = delete;singleton& operator=(const singleton& s) = delete;// 静态成员函数,用于获取单例实例,在使用时调用才创建实例static singleton& getInstance() {//创建实例static singleton instance;return instance;}//静态成员函数,单例的方法static void Work() { std::cout << "我是单例的方法" << std::endl; };
    };int main() {// 获取单例实例singleton& sg = singleton::getInstance();sg.Work();return 0;
    }
    

总结

  1. 懒汉式单例模式:与饿汉式不同,懒汉式单例在第一次需要使用时才会创建实例,避免了资源的浪费。

  2. 私有化构造函数和析构函数:保证类的实例无法在外部被创建或销毁。

  3. 删除拷贝构造和赋值运算符:避免了单例对象的复制和赋值,确保了全局只有一个实例。

  4. 静态局部变量:通过在getInstance中使用static局部变量,我们实现了懒汉式单例模式,在第一次调用时实例化,之后保持唯一。

懒汉式单例模式的优点

  • 实例只会在第一次使用时创建,节省了资源。

  • 避免了程序启动时就创建实例的开销。

缺点

  • 如果单例的创建过程很耗时,可能会导致首次调用时的延迟。

  • 在多线程环境下,虽然C++11确保了线程安全,但如果不小心修改代码,仍可能出现线程安全问题。

这种方式适用于实例创建开销较大,且程序中不会在一开始就需要该单例实例的场景。

 线程安全的懒汉模式

 使用 std::mutex 来保证线程安全

通过使用互斥锁(std::mutex),我们可以确保在多线程环境下,只有一个线程能够创建单例实例。其基本思路是每次访问getInstance时,使用锁来保护实例的创建过程。

#include <iostream>
#include <mutex>  // 引入互斥锁库class singleton {
private:singleton() {};  // 构造函数私有化~singleton() {}; // 析构函数私有化public:// 禁止拷贝和赋值singleton(const singleton& s) = delete;singleton& operator=(const singleton& s) = delete;// 静态成员函数,用于获取单例实例static singleton& getInstance() {std::lock_guard<std::mutex> lock(mtx);  // 加锁,保证线程安全if (!instance) {  // 如果实例还没有创建instance = new singleton();}return *instance;}// 单例的方法static void Work() { std::cout << "我是单例的方法" << std::endl; }private:static singleton* instance;  // 单例实例指针static std::mutex mtx;       // 互斥锁
};// 初始化静态成员变量
singleton* singleton::instance = nullptr;
std::mutex singleton::mtx;int main() {// 获取单例实例singleton& sg = singleton::getInstance();sg.Work();return 0;
}

解释:

  • std::mutex mtx;:我们添加了一个静态的std::mutex,用于控制对单例实例创建的访问。

  • std::lock_guard<std::mutex> lock(mtx);:使用lock_guard来自动加锁和解锁,保证线程在访问实例时不会发生竞争条件。

  • if (!instance):只有当instance为空时,我们才会创建单例实例。

这种方法通过互斥锁确保了多线程环境下的线程安全,但它可能会导致性能开销,特别是在锁的竞争激烈时。


工厂模式

工厂模式是一种创建型设计模式,提供了创建对象的最佳方式。在工厂模式中,我们通过工厂类来创建对象,避免暴露创建对象的细节。

简单工厂模式

一个工厂类根据传入的参数来决定创建哪个类的实例。缺点是扩展性差。

  • 🏭 简单工厂实现

    class Fruit {
    public:virtual void show() = 0;
    };
    class Apple : public Fruit {
    public:void show() { std::cout << "我是苹果" << std::endl; }
    };
    class Banana : public Fruit {
    public:void show() { std::cout << "我是香蕉" << std::endl; }
    };
    class FruitFactory {
    public:static std::shared_ptr<Fruit> create(const std::string &name) {if (name == "苹果") return std::make_shared<Apple>();else if (name == "香蕉") return std::make_shared<Banana>();return nullptr;}
    };
    

简单工厂模式通过一个工厂类来决定实例化哪个具体的产品类。它将对象的创建集中到工厂类中,客户端不需要直接创建对象,只需要通过工厂来获取。

优点:

  • 客户端解耦:客户端代码不需要知道具体产品类的创建细节,只通过工厂来获取对象,降低了客户端与产品类的耦合度。

  • 集中管理:所有产品的创建集中管理,便于修改和维护。

  • 易于扩展:增加新的产品只需要在工厂中加入相应的逻辑,不需要改动其他类的代码。

缺点:

  • 违反开闭原则:每次增加新的产品类型时,都需要修改工厂类的代码,违反了开闭原则(对扩展开放,对修改关闭)。

  • 难以扩展产品种类:如果产品种类过多,工厂类将变得臃肿,管理变得复杂。

  • 不够灵活:如果有多个工厂需要不同的产品,简单工厂模式不能很好地支持这种情况。

  • 🍏 工厂方法模式实现

    #include <iostream>
    #include <string>
    #include <memory>// ------------------------------------
    // 抽象产品类:水果类
    // ------------------------------------
    class Fruit {
    public:Fruit() {}  // 构造函数virtual void show() = 0;  // 纯虚函数,要求每个子类实现该方法
    };// ------------------------------------
    // 具体产品类:苹果类
    // ------------------------------------
    class Apple : public Fruit {
    public:Apple() {}  // 构造函数virtual void show() {std::cout << "我是一个苹果" << std::endl;  // 展示水果的名字}
    private:std::string _color;  // 苹果的颜色
    };// ------------------------------------
    // 具体产品类:香蕉类
    // ------------------------------------
    class Banana : public Fruit {
    public:Banana() {}  // 构造函数virtual void show() {std::cout << "我是一个香蕉" << std::endl;  // 展示水果的名字}
    };// ------------------------------------
    // 抽象工厂类:水果工厂类
    // ------------------------------------
    class FruitFactory {
    public:virtual std::shared_ptr<Fruit> create() = 0;  // 纯虚函数,具体工厂类需要实现此方法来创建相应的产品
    };// ------------------------------------
    // 具体工厂类:苹果工厂类
    // ------------------------------------
    class AppleFactory : public FruitFactory {
    public:virtual std::shared_ptr<Fruit> create() {return std::make_shared<Apple>();  // 创建并返回一个苹果对象}
    };// ------------------------------------
    // 具体工厂类:香蕉工厂类
    // ------------------------------------
    class BananaFactory : public FruitFactory {
    public:virtual std::shared_ptr<Fruit> create() {return std::make_shared<Banana>();  // 创建并返回一个香蕉对象}
    };// ------------------------------------
    // 主函数:演示如何使用工厂方法模式
    // ------------------------------------
    int main() {// 创建苹果工厂对象std::shared_ptr<FruitFactory> factory(new AppleFactory());  // 通过苹果工厂创建苹果产品对象std::shared_ptr<Fruit> fruit = factory->create();  fruit->show();  // 调用苹果的show方法,输出:我是一个苹果// 重置工厂为香蕉工厂对象factory.reset(new BananaFactory());  // 通过香蕉工厂创建香蕉产品对象fruit = factory->create();  fruit->show();  // 调用香蕉的show方法,输出:我是一个香蕉return 0;  
    }
    

工厂方法模式的优缺点:

优点:

  1. 减轻了工厂类的负担:通过将不同类型的产品的生产交给不同的具体工厂类,可以避免一个工厂类处理太多不同类型产品的复杂逻辑。

  2. 符合开闭原则:当需要添加新产品时,只需要创建新的工厂类并实现create()方法,而不需要修改原有的工厂类和产品类。

缺点:

  1. 类的数量增加:每增加一种新的产品类型,就需要创建一个新的工厂类,这可能导致类的数量激增,管理和维护变得困难。

  2. 需要更多的代码:每个产品的工厂都需要有一个独立的类,可能会增加代码的复杂度。

抽象工厂模式

进一步抽象出工厂结构,通过抽象工厂来创建不同系列的对象。适用于产品族的管理。

  • 🌐 抽象工厂模式实现

    #include <iostream>
    #include <string>
    #include <memory>// 抽象⼯⼚模式:围绕⼀个超级⼯⼚创建其他⼯⼚。每个⽣成的⼯⼚按照⼯⼚模式提供对象。
    // 思想:将⼯⼚抽象成两层,抽象⼯⼚ & 具体⼯⼚⼦类, 在⼯⼚⼦类中⽣产不同类型的⼦产品// 抽象水果类,定义了水果的公共接口
    class Fruit {
    public:// 构造函数Fruit() {}// 纯虚函数,用于展示水果信息,具体实现由子类完成virtual void show() = 0;
    };// 苹果类,继承自水果类,实现了具体的水果信息展示
    class Apple : public Fruit {
    public:// 构造函数Apple() {}// 实现抽象基类的纯虚函数,输出苹果信息virtual void show() {std::cout << "我是⼀个苹果" << std::endl;}
    private:// 苹果的颜色属性std::string _color;
    };// 香蕉类,继承自水果类,实现了具体的水果信息展示
    class Banana : public Fruit {
    public:// 构造函数Banana() {}// 实现抽象基类的纯虚函数,输出香蕉信息virtual void show() {std::cout << "我是⼀个⾹蕉" << std::endl;}
    };// 抽象动物类,定义了动物的公共接口
    class Animal {
    public:// 纯虚函数,用于输出动物的声音,具体实现由子类完成virtual void voice() = 0;
    };// 小羊类,继承自动物类,实现了具体的动物声音输出
    class Lamp : public Animal {
    public:// 实现抽象基类的纯虚函数,输出小羊的声音void voice() { std::cout << "咩咩咩\n"; }
    };// 小狗类,继承自动物类,实现了具体的动物声音输出
    class Dog : public Animal {
    public:// 实现抽象基类的纯虚函数,输出小狗的声音void voice() { std::cout << "汪汪汪\n"; }
    };// 抽象工厂类,定义了创建水果和动物对象的接口
    class Factory {
    public:// 纯虚函数,用于根据名称创建水果对象virtual std::shared_ptr<Fruit> getFruit(const std::string &name) = 0;// 纯虚函数,用于根据名称创建动物对象virtual std::shared_ptr<Animal> getAnimal(const std::string &name) = 0;
    };// 水果工厂类,继承自抽象工厂类,专门用于创建水果对象
    class FruitFactory : public Factory {
    public:// 实现抽象工厂类的接口,由于该工厂只负责创建水果,所以返回空指针virtual std::shared_ptr<Animal> getAnimal(const std::string &name) {return std::shared_ptr<Animal>();}// 实现抽象工厂类的接口,根据名称创建具体的水果对象virtual std::shared_ptr<Fruit> getFruit(const std::string &name) {if (name == "苹果") {return std::make_shared<Apple>();} else if (name == "⾹蕉") {return std::make_shared<Banana>();}// 如果名称不匹配,返回空指针return std::shared_ptr<Fruit>();}
    };// 动物工厂类,继承自抽象工厂类,专门用于创建动物对象
    class AnimalFactory : public Factory {
    public:// 实现抽象工厂类的接口,由于该工厂只负责创建动物,所以返回空指针virtual std::shared_ptr<Fruit> getFruit(const std::string &name) {return std::shared_ptr<Fruit>();}// 实现抽象工厂类的接口,根据名称创建具体的动物对象virtual std::shared_ptr<Animal> getAnimal(const std::string &name) {if (name == "⼩⽺") {return std::make_shared<Lamp>();} else if (name == "⼩狗") {return std::make_shared<Dog>();}// 如果名称不匹配,返回空指针return std::shared_ptr<Animal>();}
    };// 工厂生产者类,用于根据名称创建具体的工厂对象
    class FactoryProducer {
    public:// 静态方法,根据名称返回具体的工厂对象static std::shared_ptr<Factory> getFactory(const std::string &name) {if (name == "动物") {return std::make_shared<AnimalFactory>();} else {return std::make_shared<FruitFactory>();}}
    };int main()
    {// 通过工厂生产者获取水果工厂对象std::shared_ptr<Factory> fruit_factory = FactoryProducer::getFactory("水果");// 通过水果工厂创建苹果对象std::shared_ptr<Fruit> fruit = fruit_factory->getFruit("苹果");// 调用苹果对象的展示方法fruit->show();// 通过水果工厂创建香蕉对象fruit = fruit_factory->getFruit("⾹蕉");// 调用香蕉对象的展示方法fruit->show();// 通过工厂生产者获取动物工厂对象std::shared_ptr<Factory> animal_factory = FactoryProducer::getFactory("动物");// 通过动物工厂创建小羊对象std::shared_ptr<Animal> animal = animal_factory->getAnimal("⼩⽺");// 调用小羊对象的声音输出方法animal->voice();// 通过动物工厂创建小狗对象animal = animal_factory->getAnimal("⼩狗");// 调用小狗对象的声音输出方法animal->voice();return 0;
    }

抽象工厂模式通过多个具体工厂类来创建相关联的产品家族。它为每一类产品提供一个独立的工厂,客户端通过工厂接口来获取产品,而不关心具体是哪种产品。

优点:

  • 符合开闭原则:通过增加新的具体工厂类,客户端代码无需修改,符合开闭原则。只需要增加新的工厂类,而不需要修改已有代码。

  • 支持产品族的组合:如果产品之间存在某种关联或需要组合使用(例如,一个UI界面上的按钮和输入框需要配合使用),抽象工厂模式能够很方便地提供相关产品。

  • 灵活性高:可以创建一组相关的产品,可以在不同的产品之间切换,适应不同的产品需求。

缺点:

  • 复杂性较高:由于涉及多个工厂类和产品类,代码结构变得更加复杂,理解和使用上也相对较为繁琐。

  • 难以扩展新的产品族:增加新的产品族时,不仅需要增加新产品,还需要在多个工厂类中修改代码,导致扩展不够灵活。

  • 无法为单一产品创建实例:抽象工厂模式强制要求工厂创建一组相关产品,不能像简单工厂那样只创建单个产品实例。

建造者模式(Builder Pattern)

建造者模式是一种创建型设计模式,它允许你将复杂对象的构建过程与表示分离,从而使得同样的构建过程可以创建不同的表示。换句话说,建造者模式通过逐步构建和装配来创建一个复杂对象,可以让创建过程更加灵活且易于管理。

主要目的

建造者模式的主要目的是解决对象构建过程过于复杂的问题。通常,一个复杂对象由多个部分组成,且这些部分的初始化或组合顺序对对象的最终状态至关重要。建造者模式将复杂对象的构建过程分解为多个步骤,每一步完成不同的任务,而最终的产品则通过指挥者类(Director)来完成。

核心组成部分

建造者模式主要包括以下四个核心类:

  1. 抽象产品类(Product)
    代表一个复杂的对象,它由多个部件组成,这些部件由构建者类(Builder)逐步创建并组装起来。

  2. 具体产品类(Concrete Product)
    实现了抽象产品类的具体实现,它将多个部件组合成一个完整的产品。

  3. 抽象建造者类(Builder)
    定义了创建产品各个部件的接口。它规定了构建产品的步骤,并提供了对每个部件的构建接口。

  4. 具体建造者类(Concrete Builder)
    继承自抽象建造者类,具体实现了各个部件的构建方法。每个建造者负责将产品的不同部分组合成完整的产品。

  5. 指挥者类(Director)
    负责统一产品的构建过程。它通过调用建造者的方法,逐步组装产品,并最终返回构建好的产品。

代码示例

以下是一个简单的建造者模式的实现示例,模拟了一个构建“电脑”的过程:

#include <iostream>
#include <string>// 抽象产品类
class Computer {
public:virtual void show() = 0;
};// 具体产品类:表示电脑
class PC : public Computer {
public:void show() override {std::cout << "这是一个个人电脑" << std::endl;}
};class Laptop : public Computer {
public:void show() override {std::cout << "这是一个笔记本电脑" << std::endl;}
};// 抽象建造者类
class ComputerBuilder {
public:virtual void buildCPU() = 0;virtual void buildRAM() = 0;virtual void buildStorage() = 0;virtual Computer* getResult() = 0;
};// 具体建造者类:PC建造者
class PCBuilder : public ComputerBuilder {
private:PC* pc;
public:PCBuilder() {pc = new PC();}void buildCPU() override {std::cout << "为PC组装CPU" << std::endl;}void buildRAM() override {std::cout << "为PC组装内存" << std::endl;}void buildStorage() override {std::cout << "为PC组装硬盘" << std::endl;}Computer* getResult() override {return pc;}
};// 具体建造者类:Laptop建造者
class LaptopBuilder : public ComputerBuilder {
private:Laptop* laptop;
public:LaptopBuilder() {laptop = new Laptop();}void buildCPU() override {std::cout << "为Laptop组装CPU" << std::endl;}void buildRAM() override {std::cout << "为Laptop组装内存" << std::endl;}void buildStorage() override {std::cout << "为Laptop组装硬盘" << std::endl;}Computer* getResult() override {return laptop;}
};// 指挥者类
class Director {
private:ComputerBuilder* builder;
public:Director(ComputerBuilder* b) : builder(b) {}// 指挥者负责产品的建造过程void construct() {builder->buildCPU();builder->buildRAM();builder->buildStorage();}Computer* getComputer() {return builder->getResult();}
};// 客户端代码
int main() {// 创建PC产品PCBuilder* pcBuilder = new PCBuilder();Director director(pcBuilder);director.construct();Computer* pc = director.getComputer();pc->show();// 创建Laptop产品LaptopBuilder* laptopBuilder = new LaptopBuilder();director = Director(laptopBuilder);director.construct();Computer* laptop = director.getComputer();laptop->show();delete pcBuilder;delete laptopBuilder;delete pc;delete laptop;return 0;
}

解释:

  1. 抽象产品类Computer定义了产品的接口(例如show)。

  2. 具体产品类PCLaptop分别实现了Computer类,代表不同的产品类型。

  3. 抽象建造者类ComputerBuilder定义了产品构建的步骤接口,如buildCPUbuildRAM等。

  4. 具体建造者类PCBuilderLaptopBuilder实现了具体的建造过程,分别用于创建不同类型的电脑。

  5. 指挥者类Director负责指挥具体建造者来构建产品。它通过construct()方法来控制构建过程。

适用场景

  • 当一个对象的构建过程复杂,但希望通过不同的步骤实现构建时。

  • 当创建的对象可以有多个不同的表示形式时。

  • 当构建过程需要独立于对象的表示形式时。

优点:

  • 清晰的分工:各个建造者类负责具体的产品部件构建,符合单一职责原则。

  • 灵活性:可以在不改变构建过程的情况下,创建不同的产品。

  • 易于扩展:只需扩展新的具体建造者类即可创建新的产品,不需要修改已有代码。

缺点:

  • 类数量增多:需要定义多个建造者类,可能会使得代码结构相对复杂。

  • 复杂性:对于较简单的对象,使用建造者模式可能显得过于复杂。

代理模式(Proxy Pattern)

代理模式是一种结构型设计模式,其核心思想是通过一个代理对象来控制对原对象的访问。也就是说,代理对象在客户端和目标对象之间充当中介的角色,允许我们在不直接访问目标对象的情况下,对其进行操作。

主要目标

代理模式的目的是解决在某些情况下,某个对象不适合或不能直接被引用访问时,通过代理对象来进行中介访问。代理模式为目标对象的操作提供了灵活的控制,增强了程序的扩展性和可维护性。

代理模式的组成结构:

  1. 目标对象(RealSubject)
    目标对象是代理模式中真正的业务逻辑实现者,它是代理所要控制的对象。代理对象最终会将请求转发给目标对象。

  2. 代理对象(Proxy)
    代理对象负责控制对目标对象的访问,可以进行一些额外的操作,如权限控制、延迟加载、日志记录等。代理对象通常与目标对象实现相同的接口。

  3. 客户端(Client)
    客户端通过代理对象与目标对象进行交互,客户端不直接访问目标对象。

 示例:租房中的代理模式

假设有一个房东需要将房子出租,但房东本身不能直接完成所有的出租任务(如带看房、发布租房广告等),因此他决定委托给中介来完成这些工作。这里,房东是目标对象,而中介是代理对象。

代码实现

#include <iostream>
#include <string>// 目标对象:房东(RealSubject)
class Landlord {
public:void rentHouse() {std::cout << "房东:出租房子" << std::endl;}void repairHouse() {std::cout << "房东:修理房子" << std::endl;}
};// 代理对象:中介(Proxy)
class Agent {
private:Landlord* landlord;
public:Agent(Landlord* l) : landlord(l) {}// 代理方法:发布招租广告void advertise() {std::cout << "中介:发布房子招租广告" << std::endl;}// 代理方法:带客户看房void showHouse() {std::cout << "中介:带客户看房" << std::endl;}// 代理方法:代理房东出租房子void rentHouse() {advertise(); // 先发布广告showHouse(); // 带客户看房landlord->rentHouse(); // 最后房东出租房子}// 代理方法:代理房东修理房子void repairHouse() {landlord->repairHouse();}
};// 客户端代码
int main() {Landlord* landlord = new Landlord();   // 房东对象Agent* agent = new Agent(landlord);    // 代理对象(中介)// 客户端通过中介来租房和修理房子agent->rentHouse();agent->repairHouse();delete landlord;delete agent;return 0;
}

解释:

  • 目标对象(Landlord):代表房东,负责房子的出租和维修。

  • 代理对象(Agent):代表中介,负责发布广告、带看房子以及转发房东的出租和维修请求。

  • 客户端:客户端通过代理对象(中介)来租房和修理房子,代理对象控制了对房东(目标对象)的访问。

代理模式的优缺点:

优点:

  • 控制访问:代理可以控制对目标对象的访问,例如权限控制、延迟加载等。

  • 灵活性:通过代理类可以实现透明的代理和动态代理,使得可以在不修改目标类的前提下实现功能扩展。

  • 增强功能:代理模式可以在不改变目标类的基础上增加额外的功能,如日志记录、缓存等。

缺点:

  • 增加了复杂性:引入代理类会使得系统的结构变得更加复杂。

  • 性能问题:在某些情况下,代理模式会导致额外的调用层级,从而影响程序性能。


总结

设计模式提供了一种优化代码的方式,通过标准化、模块化的设计,能够帮助我们提高系统的可维护性、可扩展性和可复用性。掌握这些设计模式和原则,将有助于开发高质量的代码,并且在实际开发中轻松应对复杂问题。

🎯 掌握设计模式 = 更加优雅、灵活的编程!

相关文章:

  • 最新的30个Android Kotlin面试题
  • Python程序开发,麒麟系统模拟电脑打开文件实现
  • <c++>使用detectMultiScale的时候出现opencv.dll冲突
  • EtherCAT 分布式时钟(DC)补偿技术解析
  • 【今日半导体行业分析】2025年4月29日
  • Missashe考研日记-day30
  • 1.3 点云数据获取方式——ToF相机
  • windows如何使用cmd命令翻转屏幕
  • 高可用、高并发、高性能架构设计深度解析
  • 数据编辑器中变量的精妙计算与灵动转换​
  • 如何在 Android 上恢复已删除的照片?:简短指南
  • python3语言基础语法整理
  • 第四节:权限管理
  • verdi使用tcl脚本批量添加波形
  • 基于STM32的中点圆算法,画空心圆的函数
  • 【数据结构】图论存储结构深度解析:邻接多重表如何实现无向图O(1)删边?邻接矩阵/链表/十字链对比
  • 【Prometheus-Mongodb Exporter安装配置指南,开机自启】
  • Educational Codeforces Round 178 div2(题解ABCDE)
  • Qwen3术语解密
  • 解决调用Claude 3.7接口 403 Request not allowed问题
  • 王毅会见俄罗斯外长拉夫罗夫
  • 上海第三家“胖永辉”在浦东开业,设立了外贸产品专区
  • 马上评|“AI神医宇宙”欺诈,连演员都不请了
  • 李勇已任内蒙古乌兰察布市委副书记,曾在中央编办任职
  • AI应用大盘点:谁暴涨?谁掉队?
  • 上海超万套保租房供应高校毕业生,各项目免押、打折等优惠频出