设计模式-结构性设计模式(针对类与对象的组织结构)

针对类与对象的组织结构

类适配器模式

适配器,在生活中又称转换器。现在的手机基本都割去了3.5mm的耳机接口,此时只有有线耳机,要听歌就需要一个转换器将3.5mm接口转成手机有的type-c的接口

适配器模式(Adapter Pattern)充当两个不兼容接口之间的桥梁,属于结构型设计模式。它通过一个中间件(适配器)将一个类的接口转换成客户期望的另一个接口,使原本不能一起工作的类能够协同工作。

cpp 复制代码
#include <iostream>
#include <string>

// 父类
class ThirtyFiveMM {
public:
    std::string listenMusic() {
        return "有线耳机听歌!";
    }
};

// typeC接口
class TypeC {
public:
    virtual std::string listen() = 0; // 纯虚函数,定义接口
    virtual ~TypeC() {} // 虚析构函数
};

// 子类作适配器,继承ThirtyFiveMM,实现TypeC接口
class Adapter : public ThirtyFiveMM, public TypeC {
public:
    std::string listen() override {
        return ThirtyFiveMM::listenMusic();
    }
};

// 主方法
void main() {
    // TestSupplier supplier; // 假设TestSupplier是一个类,这里只是示例
    Adapter adapter;
    test(&adapter); // 使用适配器将35MM转换为TypeC接口
}

void test(TypeC* typec) {
    std::cout << "成功得到:" << typec->listen() << std::endl;
}

// 假设的TestSupplier类
class TestSupplier {
    // 空类,仅作为示例
};

对象适配器

因为类适配器会占用一个继承位,而java又是单继承的。如果typeC不是接口而是抽象类的话就用不了了。所以提出对象适配器:

cpp 复制代码
#include <iostream>
#include <string>

// 父类
class ThirtyFiveMM {
public:
    std::string listenMusic() {
        return "有线耳机听歌!";
    }
};

// typeC接口
class TypeC {
public:
    virtual std::string listen() = 0; // 纯虚函数,定义接口
    virtual ~TypeC() {} // 虚析构函数
};

// 适配器类,实现TypeC接口
class Adapter : public TypeC {
private:
    ThirtyFiveMM* thirtyFiveMM; // 持有35MM类型的对象
public:
    Adapter(ThirtyFiveMM* thirtyFiveMM) : thirtyFiveMM(thirtyFiveMM) {}

    std::string listen() override {
        return thirtyFiveMM->listenMusic();
    }
};

// 主方法
int main() {
    ThirtyFiveMM thirtyFiveMM; // 创建35MM类型的对象
    Adapter adapter(&thirtyFiveMM); // 创建适配器对象,传入35MM对象
    test(&adapter); // 调用test方法,传入适配器对象
    return 0;
}

void test(TypeC* typec) {
    std::cout << "成功得到:" << typec->listen() << std::endl;
}

桥接模式

选择不同的配置(零件)组成一个东西(先组一个再组一个,一层一层的基础来达到组零件的目的)

同一种产品有着不同的配置,就像手机有:运行内存 4 6 8g,存储内存:64 128 256g,芯片:骁龙 A系列 麒麟 联发科 猎户座。不能每一种配置都写一个类就太麻烦了,所以有了桥接模式,可以通过多个类桥接成一个产品类。

优势:可以通过多个维度来自由设定配置

cpp 复制代码
#include <iostream>
#include <string>

// 第一层类:继承该类可以自定义芯片类型
class AbstractPhone {
protected:
    class Size* size; // 这里是描述存储内存

public:
    AbstractPhone(class Size* size) : size(size) {}

    virtual std::string getType() = 0; // 纯虚函数,定义芯片类型
    virtual ~AbstractPhone() {
        delete size; // 释放Size对象
    }
};

// 接口及实现类
class Size {
public:
    virtual std::string getSize() = 0; // 纯虚函数,定义接口
    virtual ~Size() {} // 虚析构函数
};

class Size256G : public Size {
public:
    std::string getSize() override {
        return "256g内存";
    }
};

// 第二层类:继承该类可以自定义芯片类型和存储内存的尺度大小
class RefinedAbstractPhone : public AbstractPhone {
public:
    RefinedAbstractPhone(Size* size) : AbstractPhone(size) {}

    std::string getSize() { // 添加尺寸维度获取方式
        return size->getSize();
    }
};

// 产品类:继承第二层类,然后自定义存储内存大小和芯片种类
class HUAWEI : public RefinedAbstractPhone {
public:
    HUAWEI(Size* size) : RefinedAbstractPhone(size) {}

    std::string getType() override {
        return "华为手机"; // 返回手机品牌类型
    }
};

// 主方法
int main() {
    Size256G* size = new Size256G();
    HUAWEI huawei(size);

    std::cout << huawei.getType() << std::endl;
    std::cout << huawei.getSize() << std::endl;

    return 0;
}

组合模式

对多个组件进行统一一样的操作

组合模式实际上就是将多个组件进行组合,让用户可以对它们进行一致性处理。比如我们的文件夹,一个文件夹中可以有很多个子文件夹或是文件。

意图:通过树形结构表示对象的层次关系,使得客户端可以一致地对待单个对象和组合对象,而无需关心它们的具体类型。

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <memory>

// 组件接口
class Component {
public:
    virtual ~Component() = default;
    virtual void add(std::shared_ptr<Component> component) = 0;
    virtual void remove(std::shared_ptr<Component> component) = 0;
    virtual void display(int depth) const = 0;
};

// 叶子类:文件
class File : public Component {
private:
    std::string name;
public:
    File(const std::string& name) : name(name) {}

    void add(std::shared_ptr<Component> component) override {
        throw std::logic_error("File cannot add components");
    }

    void remove(std::shared_ptr<Component> component) override {
        throw std::logic_error("File cannot remove components");
    }

    void display(int depth) const override {
        std::cout << std::string(depth, '-') << name << std::endl;
    }
};

// 组合类:目录
class Directory : public Component {
private:
    std::string name;
    std::vector<std::shared_ptr<Component>> children;
public:
    Directory(const std::string& name) : name(name) {}

    void add(std::shared_ptr<Component> component) override {
        children.push_back(component);
    }

    void remove(std::shared_ptr<Component> component) override {
        children.erase(std::remove(children.begin(), children.end(), component), children.end());
    }

    void display(int depth) const override {
        std::cout << std::string(depth, '-') << name << std::endl;
        for (const auto& child : children) {
            child->display(depth + 1);
        }
    }
};

// 主方法
int main() {
    // 创建文件和目录
    std::shared_ptr<File> file1 = std::make_shared<File>("file1.txt");
    std::shared_ptr<File> file2 = std::make_shared<File>("file2.txt");
    std::shared_ptr<Directory> dir1 = std::make_shared<Directory>("dir1");
    std::shared_ptr<Directory> dir2 = std::make_shared<Directory>("dir2");

    // 构建树形结构
    dir1->add(file1);
    dir1->add(file2);
    dir2->add(dir1);

    // 显示树形结构
    dir2->display(0);

    return 0;
}

装饰模式

通过B类 实现对A类方法执行前后,分别多执行一些操作。类似于AOP

Base是抽象类/接口,有一个实现类实现其里面具体的业务方法。Decorator可以理解为是一个给装饰者们的一个抽象类,然后不同的装饰者再去具体继承Decorator并在业务方法前后进行修饰。

适用:业务功能前后实现一些操作。如:在支付前提醒是否需要支付xxx元。

cpp 复制代码
#include <iostream>
#include <memory>

// 顶层抽象类
class Base {
public:
    virtual void test() = 0; // 纯虚函数,定义业务方法
    virtual ~Base() = default; // 虚析构函数
};

// 业务实现类
class BaseImpl : public Base {
public:
    void test() override {
        std::cout << "我是业务方法" << std::endl; // 具体的业务方法
    }
};

// 装饰业务类
class Decorator : public Base {
protected:
    std::shared_ptr<Base> base; // 组合方式持有被装饰对象

public:
    Decorator(std::shared_ptr<Base> base) : base(base) {}

    void test() override {
        base->test(); // 调用被装饰对象的业务方法
    }
};

// 具体实现装饰业务类
class DecoratorImpl : public Decorator {
public:
    DecoratorImpl(std::shared_ptr<Base> base) : Decorator(base) {}

    void test() override {
        std::cout << "装饰方法:我是操作前逻辑" << std::endl;
        Decorator::test(); // 调用基类的test方法,即被装饰对象的业务方法
        std::cout << "装饰方法:我是操作后逻辑" << std::endl;
    }
};

// 主方法
int main() {
    std::shared_ptr<Base> base = std::make_shared<BaseImpl>();
    std::shared_ptr<DecoratorImpl> decorator = std::make_shared<DecoratorImpl>(base); // 将Base实现装饰一下
    std::shared_ptr<DecoratorImpl> outer = std::make_shared<DecoratorImpl>(decorator); // 装饰者还可以嵌套,此时是装饰两次

    decorator->test(); // 装饰一次:装饰前------业务方法------装饰后

    outer->test(); // 装饰两次:装饰前------装饰前------业务方法------装饰后------装饰后

    return 0;
}
bash 复制代码
装饰方法:我是操作前逻辑
我是业务方法
装饰方法:我是操作后逻辑
装饰方法:我是操作前逻辑
装饰方法:我是操作前逻辑
我是业务方法
装饰方法:我是操作后逻辑
装饰方法:我是操作后逻辑

代理模式

和装饰模式代码一模一样,但核心是思想不同

代理模式是讲DecoratorImpl给别人代理了,装饰模式是DecoratorImpl自己增强。

装饰模式和代理模式:

结构相同:都实现同一个接口/抽象类

作用不同:

装饰器模式强调的是增强自身,在被装饰之后你能够在被增强的类上使用增强后的功能,增强后你还是你,只不过被强化了而已;

代理模式强调要让别人帮你去做事情,以及添加一些本身与你业务没有太多关系的事情(记录日志、设置缓存等)重点在于让别人帮你做。

cpp 复制代码
//代理者需要将代理目标组合到类中
class Decorator : public Base {
protected:
    std::shared_ptr<Base> base; // 组合方式持有被装饰对象

public:
    Decorator(std::shared_ptr<Base> base) : base(base) {}

    void test() override {
        base->test(); // 调用被装饰对象的业务方法
    }
};

外观模式

可以理解为门面模式,将需要通过操作多个类实现的一个功能封装到一个类中,便于使用

当每个功能是一个系统,完成一个业务需要多个功能时就需要分别调用多个系统,此时就可以将一个业务需要使用的多个系统封装成一个门面系统,只要调用该门面系统即可完成该业务。

举例:比如现在我们设计了三个子系统,分别是排队、结婚、领证,正常情况下我们是需要分别去找这三个部门去完成的,但是现在我们通过门面统一来完成

意图:隐藏子系统的复杂性,提供一个统一的高层接口,使客户端可以更简单地使用子系统。

cpp 复制代码
#include <iostream>

// 系统一
class SubSystemA {
public:
    void test1() {
        std::cout << "排队" << std::endl;
    }
};

// 系统二
class SubSystemB {
public:
    void test2() {
        std::cout << "结婚" << std::endl;
    }
};

// 系统三
class SubSystemC {
public:
    void test3() {
        std::cout << "领证" << std::endl;
    }
};

// 门面
class Facade {
private:
    SubSystemA a;
    SubSystemB b;
    SubSystemC c;

public:
    void marry() { // 红白喜事一条龙服务
        a.test1();
        b.test2();
        c.test3();
    }
};

// 主方法
int main() {
    Facade facade;
    facade.marry();
    return 0;
}

享元模式

核心是共享。当A类方法里写了一个方法,B类中需要同样的方法就可以直接创建A类对象来调用方法或者通过一个方法工厂类收集各个方法,然后B类通过工厂类调用A类方法

享元模式的核心在于共享对象,以减少对象的创建次数,节省内存。

意图:通过共享对象来减少内存占用,提高系统的性能,特别是在需要频繁创建大量相似对象的场景中。

cpp 复制代码
#include <iostream>

// A类
class DBUtil {
public:
    void selectDB() {
        std::cout << "我是数据库操作..." << std::endl;
    }
};

// 享元工厂
class DBUtilFactory {
private:
    static DBUtil* UTIL; // 享元对象被存放在工厂中

public:
    static DBUtil* getFlyweight() { // 获取享元对象
        if (UTIL == nullptr) {
            UTIL = new DBUtil();
        }
        return UTIL;
    }

    // 防止拷贝和赋值
    DBUtilFactory(const DBUtilFactory&) = delete;
    DBUtilFactory& operator=(const DBUtilFactory&) = delete;

    // 析构函数,释放资源
    ~DBUtilFactory() {
        delete UTIL;
    }
};

// 初始化静态成员变量
DBUtil* DBUtilFactory::UTIL = nullptr;

// B类
class UserService { // 用户服务
public:
    void service() {
        DBUtil* util = DBUtilFactory::getFlyweight(); // 通过享元工厂拿到DBUtil对象
        util->selectDB(); // 该干嘛干嘛
    }
};

// 主方法
int main() {
    UserService userService;
    userService.service(); // 调用用户服务

    return 0;
}
相关推荐
Asort3 小时前
JavaScript设计模式(四)——建造者模式:优雅构建复杂对象的实用指南
前端·javascript·设计模式
星空寻流年4 小时前
设计模式第四章(组合模式)
设计模式·组合模式
笨手笨脚の4 小时前
设计模式-组合模式
设计模式·组合模式·结构型设计模式·设计模式之美
yujkss4 小时前
23种设计模式之【抽象工厂模式】-核心原理与 Java实践
java·设计模式·抽象工厂模式
PaoloBanchero7 小时前
Unity 虚拟仿真实验中设计模式的使用 ——命令模式(Command Pattern)
unity·设计模式·命令模式
大飞pkz7 小时前
【设计模式】桥接模式
开发语言·设计模式·c#·桥接模式
BeyondCode程序员10 小时前
设计原则讲解与业务实践
设计模式·架构
青草地溪水旁10 小时前
设计模式(C++)详解——迭代器模式(1)
c++·设计模式·迭代器模式
青草地溪水旁10 小时前
设计模式(C++)详解——迭代器模式(2)
java·c++·设计模式·迭代器模式