• 设计模式(2) - 创建型模式


    创建型模式指的是 创建对象 或是 获取实例 的方式。

    1、工厂模式

    平时写一些简单的代码可能会直接用 new 创建出一个对象,但是实际在阅读一些功能比较多、规模比较庞大的工程时,可能会发现有多个类继承于同一个基类的情况,它们拥有同样的接口但是实现了不同的功能。它们可能是可以互相替代的两套系统(例如 Android Media 中的 ACodec 和 CCodec),也有可能是多个不同功能的工具(例如 MediaExtractor 中不同的 extractor),创建这类对象时往往都用到了工厂模式

    这里的工厂模式我觉得是一个广义的概念,指的是在创建有具有相同特征(相同基类)的对象时不要硬编码(hard code),这样会在工程庞大之后变得难以维护,我们需要一种动态的创建方法,可以根据条件灵活创建具体的类。这里的创建方法并不仅仅指的是如下三种具体的工厂设计模式,也有可能是一个条件判断函数。

    工厂模式的实现主要依赖的是多态的特性。

    1.1、简单工厂模式

    我们可以认为具有相同特征(相同基类)的对象可以由一个工厂生产,根据不同的要求,工厂可以生产不同的对象实例,这就是简单工厂模式。

    以简单计算器为例,有加法和减法等等计算器类型,这时候我们就可以创建一个计算器工厂,根据传进的符号创建对应的计算器实例:

    class Calculator {
    public:
    	virtual int calculate(int a, int b) = 0;
    };
    
    class AddCalculator : public Calculator {
    public:
    	int calculate(int a, int b) {
    		return a + b;
    	}
    };
    
    class SubCalculator : public Calculator {
    public:
    	int calculate(int a, int b) {
    		return a - b;
    	}
    };
    
    class CalculatorFactory {
    public:
    	static Calculator* createCalculator(const char c) {
    		Calculator* cal = NULL;
    		switch (c)
    		{
    		case '+':
    			cal = new AddCalculator;
    			break;
    		case '-':
    			cal = new SubCalculator;
    			break;
    		default:
    			break;
    		}
    		return cal;
    	}
    };
    
    int main() {
    	Calculator* addCal = CalculatorFactory::createCalculator('+');
    	printf("5 + 5 = %d\n", addCal->calculate(5, 5));
    	Calculator* subCal = CalculatorFactory::createCalculator('-');
    	printf("5 - 5 = %d\n", subCal->calculate(5, 5));
    	delete addCal;
    	delete subCal;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    请添加图片描述

    用简单工厂模式有什么好处呢?

    • 只要给工厂指定计算器类型,它就可以为我们创建出对应实例,创建实例的接口被统一,后期如果要修改对象类型,只需要修改传给工厂的参数即可;
    • 后期如何要增加新的计算器类型,我们只要修改工厂即可,使用方式仍旧可以保持统一。

    1.2、工厂方法模式

    简单工厂需要指定创建的实例类型,指定这个动作也可以看作为hard code的一种,有没有办法让工厂为我们自动选择创建的实例类型呢?工厂方法模式可以帮助我们完成自动选择的动作。

    我们对上面简单计算器例子做一些修改:

    class Calculator {
    public:
    	virtual int calculate(int a, int b) = 0;
    };
    
    class AddCalculator : public Calculator {
    public:
    	int calculate(int a, int b) {
    		return a + b;
    	}
    };
    
    class SubCalculator : public Calculator {
    public:
    	int calculate(int a, int b) {
    		return a - b;
    	}
    };
    
    class CalFactory {
    public:
    	virtual Calculator* createCalculator() = 0;
    };
    
    class AddCalFactory : public CalFactory {
    public:
    	Calculator* createCalculator() {
    		return new AddCalculator;
    	}
    };
    
    class SubCalFactory : public CalFactory {
    public:
    	Calculator* createCalculator() {
    		return new SubCalculator;
    	}
    };
    
    int main() {
    
    	CalFactory *addFactory = new AddCalFactory;
    	Calculator* addCal = addFactory->createCalculator();
    	printf("5 + 5 = %d\n", addCal->calculate(5, 5));
    	CalFactory *subFactory = new SubCalFactory;
    	Calculator* subCal = subFactory->createCalculator();
    	printf("5 - 5 = %d\n", subCal->calculate(5, 5));
    	delete addCal;
    	delete subCal;
    	delete addFactory;
    	delete subFactory;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    请添加图片描述
    例子中每一个 Calculator 类都有其对应的 CalFactory 工厂,想要创建需要的类型只要实例化对应的工厂就可以了。

    我们在网上其他博客中看到的工厂方法模式一般到这里就结束了,这里就会有疑问了,自动选择是如何体现的呢?工厂方法模式相比简单工厂优点在哪里呢?

    接下来以 Android MediaPlayerFactory 为例看一下工厂方法模式在实战中是如何使用的:

    MediaPlayerFactory 中有一个 getPlayerType 方法,它会遍历每一个具体的 IFactory,调用它们的 scoreFactory 方法得到最优分数,得到最优工厂类型;然后再调用MediaPlayerFactory createPlayer 方法,用自动选择的工厂创建出实例(当然分数选择和实例化对象可以放到一个方法中)。

    请添加图片描述

    1.3、抽象工厂模式

    抽象工厂和工厂方法类似,这里只做简单举例:

    class Pencil {
    public:
    	Pencil(const char* factory) : mFactory(factory) {}
    	virtual void write() = 0;
    protected:
    	const char* mFactory;
    };
    
    class RedPencil : public Pencil {
    public:
    	RedPencil(const char* factory) : Pencil(factory) {}
    	void write() {
    		printf("%s", mFactory);
    		printf(" Red Pencil write\n");
    	}
    };
    
    class BlackPencil : public Pencil {
    public:
    	BlackPencil(const char* factory) : Pencil(factory) {}
    	void write() {
    		printf("%s", mFactory);
    		printf(" Black Pencil write\n");
    	}
    };
    
    class Pen {
    public:
    	Pen(const char* factory) : mFactory(factory) {}
    	virtual void write() = 0;
    protected:
    	const char* mFactory;
    };
    
    class RedPen : public Pen {
    public:
    	RedPen(const char* factory) : Pen(factory) {}
    	void write() {
    		printf("%s", mFactory);
    		printf(" Red Pen write\n");
    	}
    };
    
    class BlackPen : public Pen {
    public:
    	BlackPen(const char* factory) : Pen(factory) {}
    	void write() {
    		printf("%s", mFactory);
    		printf(" Black Pen write\n");
    	}
    };
    
    
    class Factory {
    public:
    	virtual Pencil* createPencil(int catgory) = 0;
    	virtual Pen* createPen(int catgory) = 0;
    };
    
    class AppleFactory : public Factory {
    public:
    	virtual Pencil* createPencil(int catgory) {
    		Pencil* p = NULL;
    		switch (catgory)
    		{
    		case 1:
    			p = new RedPencil("AppleFactory");
    			break;
    		case 2:
    			p = new BlackPencil("AppleFactory");
    			break;
    		default:
    			break;
    		}
    		return p;
    	}
    	virtual Pen* createPen(int catgory) {
    		Pen* p = NULL;
    		switch (catgory)
    		{
    		case 1:
    			p = new RedPen("AppleFactory");
    			break;
    		case 2:
    			p = new BlackPen("AppleFactory");
    			break;
    		default:
    			break;
    		}
    		return p;
    	}
    };
    
    class OrangeFactory : public Factory {
    public:
    	virtual Pencil* createPencil(int catgory) {
    		Pencil* p = NULL;
    		switch (catgory)
    		{
    		case 1:
    			p = new RedPencil("OrangeFactory");
    			break;
    		case 2:
    			p = new BlackPencil("OrangeFactory");
    			break;
    		default:
    			break;
    		}
    		return p;
    	}
    	virtual Pen* createPen(int catgory) {
    		Pen* p = NULL;
    		switch (catgory)
    		{
    		case 1:
    			p = new RedPen("OrangeFactory");
    			break;
    		case 2:
    			p = new BlackPen("OrangeFactory");
    			break;
    		default:
    			break;
    		}
    		return p;
    	}
    };
    
    static Factory* createFactory(const char* factoryName) {
    	Factory* factory = NULL;
    	if (!memcmp(factoryName, "Apple", 5))
    	{
    		factory = new AppleFactory;
    	}
    	else if (!memcmp(factoryName, "Orange", 6)) {
    		factory = new OrangeFactory;
    	}
    	return factory;
    }
    
    int main() {
    	Factory* AppFac = createFactory("Apple");
    	Pen* AppPen = AppFac->createPen(1);
    	AppPen->write();
    	Pencil* AppPencil = AppFac->createPencil(1);
    	AppPencil->write();
    
    	Factory* OraFac = createFactory("Orange");
    	Pen* OraPen = OraFac->createPen(2);
    	OraPen->write();
    	Pencil* OraPencil = OraFac->createPencil(2);
    	OraPencil->write();
    
    	delete AppFac;
    	delete AppPen;
    	delete AppPencil;
    	delete OraFac;
    	delete OraPen;
    	delete OraPencil;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159

    2、建造者模式

    class Builder;
    class Computer {
    protected:
    	friend class Builder;
    	void setBrand(std::string brand)	{ mBrand = brand; }
    	void setCpu(std::string cpu)		{ mCpu = cpu; }
    	void setGpu(std::string gpu)		{ mGpu = gpu; }
    	void setPrice(int price)			{ mPrice = price; }
    public:
    	void print() {
    		printf("%s \t %s \t %s \t %d\n", mBrand.c_str(), mCpu.c_str(), mGpu.c_str(), mPrice);
    	}
    private:
    	std::string mBrand;
    	std::string mCpu;
    	std::string mGpu;
    	int			mPrice;
    };
    
    class GrapeComputer : public Computer {
    public:
    	GrapeComputer() {
    		setBrand("Grape");
    		setGpu("RTX4080");
    	}
    };
    
    class OrangeComputer : public Computer {
    public:
    	OrangeComputer() {
    		setBrand("Orange");
    	}
    };
    
    class Director;
    class Builder {
    protected:
    	friend class Director;
    	virtual void buildCpu(std::string cpu) { mComputer->setCpu(cpu); };
    	virtual void buildGpu(std::string gpu) { mComputer->setGpu(gpu); };
    	virtual void buildPrice(int price) { mComputer->setPrice(price); };
    public:
    	virtual Computer* build() {
    		return mComputer;
    	}
    protected:
    	Computer *mComputer;
    };
    
    class GrapeBuilder : public Builder
    {
    public:
    	GrapeBuilder() {
    		mComputer = new GrapeComputer();
    	}
    	virtual void buildGpu(std::string gpu) override { };
    };
    
    class OrangeBuilder : public Builder
    {
    public:
    	OrangeBuilder() {
    		mComputer = new OrangeComputer();
    	}
    };
    
    
    class Director {
    public:
    	Director(Builder *builder) { mBuilder = builder; }
    	Computer * construct(std::string cpu, std::string gpu, int price) {
    		mBuilder->buildCpu(cpu);
    		mBuilder->buildGpu(gpu);
    		mBuilder->buildPrice(price);
    		return mBuilder->build();
    	}
    private:
    	Builder *mBuilder;
    };
    
    int main() {
    	Builder *grapeBuilder = new GrapeBuilder;
    	Director *directorA = new Director(grapeBuilder);
    	Computer *grapeComputer = directorA->construct("core i7 13700k", "standard", 10999);
    	grapeComputer->print();
    	delete grapeBuilder;
    	delete directorA;
    	delete grapeComputer;
    
    	Builder *orangeBuilder = new OrangeBuilder;
    	Director *directorB = new Director(orangeBuilder);
    	Computer *orangeComputer = directorB->construct("core i5 12400f", "RTX3060", 5999);
    	orangeComputer->print();
    	delete orangeBuilder;
    	delete directorB;
    	delete orangeComputer;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97

    以上是我阅读网上内容后自己编写的示例,示例主要由 Director 和 Builder 两部分组成。我的理解 Director 就是调用者,不同的 Builder 用于处理不同事务/创建不同的对象。引用网上的分析:

    在客户端代码中,无须关心产品对象的具体组装过程,只需确定具体建造者的类型即可,建造者模式将复杂对象的构建与对象的表现分离开来,这样使得同样的构建过程可以创建出不同的表现。

    我没有在实战中看到过完全契合以上示例的建造者模式使用,只在
    Android MediaCodecList.cpp中看到有类似的使用方法。

    实例化 MediaCodecList 时会先调用 GetBuilders 获取 Codec2InfoBuilder 和 OmxInfoBuilder 实例,接着遍历调用他们的 buildMediaCodecList 方法,将所有的信息写到 MediaCodecListWriter 中。在这个示例中虽然没有具体的 Director,也没有返回具体的对象,只有不同的 Builder,但是我觉得和建造者模式的思想是一致的。

    3、单例模式

    单例模式比较简单,在我们不想重复构建一个对象的时候可以使用单例模式,例如 DataSourceFactory.cpp 和上面提到的 MediaCodecList.cpp 就是典型的单例模式:

    struct MediaCodecList : public BnMediaCodecList {
    	static sp<IMediaCodecList> getInstance();
    private:
        static sp<IMediaCodecList> sCodecList;
        MediaCodecList(std::vector<MediaCodecListBuilderBase*> builders);
        MediaCodecList(const MediaCodecList&) = delete;
        MediaCodecList& operator=(const MediaCodecList&) = delete;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    目前碰到的单例模式使用场景如下:

    • 加载并存储信息可供查询,使用单例模式可以避免多次信息加载(MediaCodecList)
    • 提供一系列方法可供使用,使用单例模式可以减少对象创建的开销(DataSourceFactory)。

    唯一有一点要注意的,在获取对象实例时需要用锁保护,避免有同时调用getInstance 同时创建到对象的情况出现:

    sp<DataSourceFactory> DataSourceFactory::getInstance() {
        Mutex::Autolock l(sInstanceLock);
        if (!sInstance) {
            sInstance = new DataSourceFactory();
        }
        return sInstance;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    聊一聊EGO-Planner膨胀系数的大小对无人机避障飞行的影响
    制作linux系统内部yum源仓库
    矩阵论理论知识(三)特殊的线性空间
    【动态规划-简单】剑指 Offer 10- II. 青蛙跳台阶问题
    linux——(5 部分软件安装)
    asp毕业设计——基于asp+access的网页设计辅导系统设计与实现(毕业论文+程序源码)——网页设计辅导系统
    kotlin flow sample的用法
    Elasticsearch:在 Elastic 中访问机器学习模型
    Eclipse官网下载历史版本
    LeetCode·23.合并K个升序链表·递归·迭代
  • 原文地址:https://blog.csdn.net/qq_41828351/article/details/132724052