23种设计模式-7种结构模式

结构型模式简述

把类或对象结合在一起形成一个更大的结构。

装饰器模式:动态的给对象添加新的功能。

代理模式:为其它对象提供一个代理以便控制这个对象的访问。

桥接模式:将抽象部分和它的实现部分分离,使它们都可以独立的变化。

适配器模式:将一个类的方法接口转换成客户希望的另一个接口。

组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构。

外观模式:对外提供一个统一的方法,来访问子系统中的一群接口。

享元模式:通过共享技术来有效的支持大量细粒度的对象。

模式C++代码实现

桥接模式

桥接模式(Bridge Pattern)是一种结构性设计模式,用于将抽象部分与其实现部分分离,使它们可以独立地变化。桥接模式通过将多维度的类层次结构分为两个独立的继承层次结构,从而提高了系统的可扩展性和灵活性。

以下是一个使用C++实现桥接模式的简单示例,假设我们要实现不同类型的电视和遥控器的桥接模式:

#include 

// 实现部分
class TV {
public:
    virtual void turnOn() = 0;
    virtual void turnOff() = 0;
};

class SonyTV : public TV {
public:
    void turnOn() override {
        std::cout << "Sony TV is turned on" << std::endl;
    }

    void turnOff() override {
        std::cout << "Sony TV is turned off" << std::endl;
    }
};

class LGTV : public TV {
public:
    void turnOn() override {
        std::cout << "LG TV is turned on" << std::endl;
    }

    void turnOff() override {
        std::cout << "LG TV is turned off" << std::endl;
    }
};

// 抽象部分
class RemoteControl {
protected:
    TV* tv;

public:
    RemoteControl(TV* tv) : tv(tv) {}

    virtual void turnOn() {
        tv->turnOn();
    }

    virtual void turnOff() {
        tv->turnOff();
    }
};

class BasicRemoteControl : public RemoteControl {
public:
    BasicRemoteControl(TV* tv) : RemoteControl(tv) {}

    void turnOn() override {
        std::cout << "Basic Remote: ";
        RemoteControl::turnOn();
    }

    void turnOff() override {
        std::cout << "Basic Remote: ";
        RemoteControl::turnOff();
    }
};

class AdvancedRemoteControl : public RemoteControl {
public:
    AdvancedRemoteControl(TV* tv) : RemoteControl(tv) {}

    void mute() {
        std::cout << "Advanced Remote: Muted" << std::endl;
    }
};

int main() {
    TV* sonyTV = new SonyTV();
    TV* lgTV = new LGTV();

    RemoteControl* basicRemoteSony = new BasicRemoteControl(sonyTV);
    RemoteControl* advancedRemoteLG = new AdvancedRemoteControl(lgTV);

    basicRemoteSony->turnOn();
    basicRemoteSony->turnOff();

    advancedRemoteLG->turnOn();
    advancedRemoteLG->mute();
    advancedRemoteLG->turnOff();

    delete sonyTV;
    delete lgTV;
    delete basicRemoteSony;
    delete advancedRemoteLG;

    return 0;
}

在这个示例中,TV 类表示实现部分,SonyTVLGTV 是其具体实现。RemoteControl 类表示抽象部分,BasicRemoteControlAdvancedRemoteControl 是其具体实现。通过使用桥接模式,我们可以轻松地将不同的遥控器与不同的电视组合,实现了抽象部分和实现部分的解耦。

装饰模式

装饰模式(Decorator Pattern)是一种结构性设计模式,允许在不改变已有对象的结构的情况下,动态地将功能添加到对象上。在装饰模式中,通过创建装饰器类,将装饰器类与被装饰的类组合,从而实现功能的叠加和扩展。

以下是一个使用C++实现装饰模式的简单示例,假设我们要实现不同类型的咖啡以及可以添加调料的功能:

#include 
#include 

// 基础咖啡类(被装饰的类)
class Coffee {
public:
    virtual std::string getDescription() const {
        return "Basic Coffee";
    }

    virtual double cost() const {
        return 1.0;
    }
};

// 调料装饰器类
class CoffeeDecorator : public Coffee {
protected:
    Coffee* coffee;

public:
    CoffeeDecorator(Coffee* coffee) : coffee(coffee) {}

    std::string getDescription() const override {
        return coffee->getDescription();
    }

    double cost() const override {
        return coffee->cost();
    }
};

// 具体的调料装饰器类
class MilkDecorator : public CoffeeDecorator {
public:
    MilkDecorator(Coffee* coffee) : CoffeeDecorator(coffee) {}

    std::string getDescription() const override {
        return coffee->getDescription() + ", Milk";
    }

    double cost() const override {
        return coffee->cost() + 0.5;
    }
};

class SugarDecorator : public CoffeeDecorator {
public:
    SugarDecorator(Coffee* coffee) : CoffeeDecorator(coffee) {}

    std::string getDescription() const override {
        return coffee->getDescription() + ", Sugar";
    }

    double cost() const override {
        return coffee->cost() + 0.2;
    }
};

int main() {
    Coffee* basicCoffee = new Coffee();
    Coffee* milkCoffee = new MilkDecorator(basicCoffee);
    Coffee* milkSugarCoffee = new SugarDecorator(milkCoffee);

    std::cout << "Description: " << milkSugarCoffee->getDescription() << std::endl;
    std::cout << "Cost: $" << milkSugarCoffee->cost() << std::endl;

    delete basicCoffee;
    delete milkCoffee;
    delete milkSugarCoffee;

    return 0;
}

在这个示例中,Coffee 类表示被装饰的基础咖啡,CoffeeDecorator 类表示调料装饰器。具体的调料装饰器类如 MilkDecoratorSugarDecorator 继承自 CoffeeDecorator,并通过重写 getDescriptioncost 方法来添加调料的描述和价格。通过组合不同的装饰器,我们可以在运行时动态地为咖啡添加不同的调料。

适配器模式

适配器模式(Adapter Pattern)是一种结构性设计模式,它允许将不兼容的接口转换成客户端期望的接口。适配器模式通常用于连接两个不兼容的接口,使它们可以一起工作。

以下是一个使用C++实现适配器模式的简单示例,假设我们有一个已有的音频播放器接口和一个新的MP3播放器类,我们需要将MP3播放器接口适配成音频播放器接口。

#include 
#include 

// 旧的音频播放器接口
class AudioPlayer {
public:
    virtual void playAudio(const std::string& audioType, const std::string& fileName) = 0;
};

// 新的MP3播放器类
class Mp3Player {
public:
    void playMp3(const std::string& fileName) {
        std::cout << "Playing MP3 file: " << fileName << std::endl;
    }
};

// 适配器类,将Mp3Player适配成AudioPlayer接口
class Mp3Adapter : public AudioPlayer {
private:
    Mp3Player mp3Player;

public:
    void playAudio(const std::string& audioType, const std::string& fileName) override {
        if (audioType == "mp3") {
            mp3Player.playMp3(fileName);
        }
    }
};

int main() {
    AudioPlayer* audioPlayer = new Mp3Adapter();

    audioPlayer->playAudio("mp3", "song.mp3");
    audioPlayer->playAudio("wma", "song.wma"); // 这不会播放,因为适配器只支持MP3

    delete audioPlayer;

    return 0;
}

在这个示例中,AudioPlayer 是旧的音频播放器接口,Mp3Player 是新的MP3播放器类,Mp3Adapter 是适配器类,它继承自 AudioPlayer 并包含一个 Mp3Player 对象。适配器类的 playAudio 方法将传入的 audioType 参数与适配的格式进行比较,如果是 “mp3” 格式,就调用 Mp3Player 的方法来播放。

通过适配器模式,我们可以在不改变已有代码的情况下,将不兼容的MP3播放器接口适配成了音频播放器接口,从而让它们可以一起工作。

外观模式

外观模式(Facade Pattern)是一种结构性设计模式,它为复杂的子系统提供一个统一的接口,使得外部客户端可以更简单地使用该子系统,而不需要了解其内部的复杂逻辑。

以下是一个使用C++实现外观模式的简单示例,假设我们有一个复杂的电子设备系统,包括电视、音响和灯光等组件,我们可以使用外观模式来创建一个统一的接口以简化客户端的操作。

#include 

// 子系统:电视
class TV {
public:
    void turnOn() {
        std::cout << "TV is on" << std::endl;
    }

    void turnOff() {
        std::cout << "TV is off" << std::endl;
    }
};

// 子系统:音响
class Stereo {
public:
    void turnOn() {
        std::cout << "Stereo is on" << std::endl;
    }

    void turnOff() {
        std::cout << "Stereo is off" << std::endl;
    }
};

// 子系统:灯光
class Lights {
public:
    void turnOn() {
        std::cout << "Lights are on" << std::endl;
    }

    void turnOff() {
        std::cout << "Lights are off" << std::endl;
    }
};

// 外观类:家庭影院
class HomeTheaterFacade {
private:
    TV tv;
    Stereo stereo;
    Lights lights;

public:
    void watchMovie() {
        std::cout << "Get ready to watch a movie!" << std::endl;
        tv.turnOn();
        stereo.turnOn();
        lights.turnOff();
    }

    void endMovie() {
        std::cout << "Movie is over, shutting down..." << std::endl;
        tv.turnOff();
        stereo.turnOff();
        lights.turnOn();
    }
};

int main() {
    HomeTheaterFacade homeTheater;

    homeTheater.watchMovie();
    std::cout << "----------------------" << std::endl;
    homeTheater.endMovie();

    return 0;
}

在这个示例中,TVStereoLights 分别表示不同的电子设备子系统。HomeTheaterFacade 是外观类,它封装了对各个子系统的操作,提供了 watchMovieendMovie 方法来统一操作电视、音响和灯光等组件,从而让客户端更简单地操作整个家庭影院。

通过外观模式,我们将复杂的子系统封装成一个简单的接口,使得客户端不需要了解子系统的复杂性,只需通过外观类来操作整个系统。

组合模式

组合模式(Composite Pattern)是一种结构性设计模式,它允许将对象组合成树形结构,以表示“部分-整体”的层次结构。组合模式使得客户端可以统一处理单个对象和对象组合,而不需要区分它们的具体类型。

以下是一个使用C++实现组合模式的简单示例,假设我们要创建一个文件系统的层次结构,包括文件和文件夹。文件夹可以包含文件和其他文件夹,形成一个树形结构。

#include 
#include 

// 组件抽象基类
class FileSystemComponent {
public:
    virtual void display() const = 0;
};

// 文件类
class File : public FileSystemComponent {
private:
    std::string name;

public:
    File(const std::string& n) : name(n) {}

    void display() const override {
        std::cout << "File: " << name << std::endl;
    }
};

// 文件夹类
class Folder : public FileSystemComponent {
private:
    std::string name;
    std::vector components;

public:
    Folder(const std::string& n) : name(n) {}

    void addComponent(FileSystemComponent* component) {
        components.push_back(component);
    }

    void display() const override {
        std::cout << "Folder: " << name << std::endl;
        for (const auto& component : components) {
            component->display();
        }
    }
};

int main() {
    File file1("file1.txt");
    File file2("file2.txt");
    File file3("file3.txt");

    Folder folder1("folder1");
    folder1.addComponent(&file1);
    folder1.addComponent(&file2);

    Folder folder2("folder2");
    folder2.addComponent(&file3);

    Folder root("root");
    root.addComponent(&folder1);
    root.addComponent(&folder2);

    root.display();

    return 0;
}

在这个示例中,FileSystemComponent 是组件的抽象基类,包括了 FileFolder 类。File 表示文件,Folder 表示文件夹,文件夹可以包含文件和其他文件夹。通过使用组合模式,我们可以将文件和文件夹组合成一个层次结构,使得客户端可以统一地处理不同层次的组件。

通过组合模式,我们可以轻松地创建复杂的层次结构,同时可以使用统一的接口来操作整个结构。这种模式在处理递归结构时特别有用,例如文件系统、组织架构等。

代理模式

代理模式(Proxy Pattern)是一种结构性设计模式,它提供了一个代理对象,用于控制对原始对象的访问。代理对象可以作为原始对象的替代,用于控制、管理或增强原始对象的访问。

以下是一个使用C++实现代理模式的简单示例,假设我们有一个图片加载器,可以从磁盘加载图片并显示。我们可以使用代理模式创建一个代理图片加载器,用于控制图片的加载和显示。

#include 
#include 

// 抽象主题
class Image {
public:
    virtual void display() = 0;
};

// 真实主题
class RealImage : public Image {
private:
    std::string filename;

public:
    RealImage(const std::string& file) : filename(file) {
        loadFromDisk();
    }

    void display() override {
        std::cout << "Displaying image: " << filename << std::endl;
    }

    void loadFromDisk() {
        std::cout << "Loading image: " << filename << std::endl;
    }
};

// 代理类
class ProxyImage : public Image {
private:
    RealImage* realImage;
    std::string filename;

public:
    ProxyImage(const std::string& file) : filename(file), realImage(nullptr) {}

    void display() override {
        if (realImage == nullptr) {
            realImage = new RealImage(filename);
        }
        realImage->display();
    }
};

int main() {
    Image* image = new ProxyImage("image.jpg");

    // 图片未加载,调用display会加载并显示
    image->display();

    // 图片已加载,直接显示
    image->display();

    return 0;
}

在这个示例中,Image 是抽象主题接口,定义了图片的显示方法。RealImage 是真实主题类,实现了图片加载和显示的功能。ProxyImage 是代理类,持有一个真实主题的实例,在需要时创建并控制真实主题的访问。

通过代理模式,我们可以延迟真实主题的创建和加载,只有在需要时才会真正地创建和加载对象。代理可以用于实现懒加载、权限控制、缓存等功能,从而对原始对象的访问进行了增强或控制。

享元模式

享元模式(Flyweight Pattern)是一种结构性设计模式,旨在通过共享对象来最大程度地减少内存使用和对象创建的开销。它适用于存在大量相似对象的场景,通过共享这些相似部分,可以有效减少内存占用。

以下是一个使用C++实现享元模式的简单示例,假设我们要创建一个文字编辑器,需要创建大量的字符对象。我们可以使用享元模式来共享相同字符的实例,以减少内存使用。

#include 
#include 

// 字符类,享元类
class Character {
private:
    char symbol;

public:
    Character(char c) : symbol(c) {}

    char getSymbol() const {
        return symbol;
    }

    void display(int pointSize) {
        std::cout << "Character: " << symbol << " Point size: " << pointSize << std::endl;
    }
};

// 字符工厂,负责创建和管理字符实例
class CharacterFactory {
private:
    std::unordered_map characters;

public:
    Character* getCharacter(char c) {
        if (characters.find(c) == characters.end()) {
            characters[c] = new Character(c);
        }
        return characters[c];
    }
};

int main() {
    CharacterFactory characterFactory;

    // 创建并显示字符实例
    Character* c1 = characterFactory.getCharacter('A');
    c1->display(12);

    Character* c2 = characterFactory.getCharacter('B');
    c2->display(16);

    // 再次获取相同字符实例
    Character* c3 = characterFactory.getCharacter('A');
    c3->display(20);

    // 释放资源
    delete c1;
    delete c2;

    return 0;
}

在这个示例中,Character 是享元类,表示一个字符对象。CharacterFactory 是字符工厂类,负责创建和管理字符实例。通过使用享元模式,我们可以共享相同字符的实例,从而减少了内存的使用。

享元模式的关键是将对象的共享和非共享状态分离,共享状态可以被多个对象共享,非共享状态可以通过参数传递给对象。这样可以在一定程度上减少对象的创建和内存占用。

你可能感兴趣的:(设计模式,结构型设计模式,装饰器模式)