C++设计模式-创建型设计模式:抽象工厂

目录

抽象工厂介绍-定义、结构、参考实现、场景

场景

如何设计

定义

本质:选择产品簇的实现,优缺点

何时选用抽象工厂:强调一系列相关产品接口、联合使用它们的时候

抽象工厂模式的工程应用-控件式开发


抽象工厂介绍-定义、结构、参考实现、场景

场景

  • 完成两套GUI的表示层,一个在PC,另一个在平板、手机上的应用程序界面
  • 通常一个显著的设备差别在于分辨率

如何设计

  • 从封装的角度来讲,希望根据布局器来配置i我们的控件,我们开放布局器接口控件接口,供客户端调用

首先来看不使用设计模式的做法:

#include <iostream>
using namespace std;

class FrameApi {
public:
	virtual void draw() = 0;
protected:
	FrameApi() {}
};

class LayoutApi {
public:
	virtual void installFrame() = 0;
protected:
	LayoutApi() {}
};

//PC Frame
class ComputerFrame :public FrameApi {
public:
	ComputerFrame(int pins) :m_pins(pins) {}
	void draw() {
		cout << "现在是PC Frame,分辨率适用:" << m_pins << endl;
	}
private:
	int m_pins;
};
//Mobile Frame
class MobileFrame :public FrameApi {
public:
	MobileFrame(int pins) :m_pins() {}
	void draw() {
		cout << "现在是Mobile Frame,分辨率适用:" << m_pins << endl;
	}
private:
	int m_pins;
};

//高分辨率布局
class HighLayout :public LayoutApi {
public:
	HighLayout(int FrameAdapterPins) :m_FrameAdapterPins(FrameAdapterPins) {}
	void installFrame() {
		cout << "现在是在PC环境下使用高分辨率布局" << m_FrameAdapterPins << endl;
	}
private:
	int m_FrameAdapterPins;
};

//低分辨率布局
class LowLayout :public LayoutApi {
public:
	LowLayout(int FrameAdapterPins) :m_FrameAdapterPins(FrameAdapterPins) {}
	void installFrame() {
		cout << "现在是在Mobile环境下使用低分辨率布局" << m_FrameAdapterPins << endl;
	}
private:
	int m_FrameAdapterPins;
};

//创建产品的简单工厂
class FrameFactory {
public:
	static FrameApi* createFrame(int type) {
		if (type == 1)return new ComputerFrame(1024);
		if (type == 2)return new MobileFrame(800);
		return nullptr;
	}
};

class LayoutFactory {
public:
	static LayoutApi* createLayout(int type) {
		if (type == 1)return new HighLayout(1024);
		if (type == 2)return new LowLayout(800);
		return nullptr;
	}
};

class GUIEngineer {
public:
	void prepareDraw(int FrameType, int LayoutType) {
		this->pFrame = FrameFactory::createFrame(FrameType);
		this->pLayout = LayoutFactory::createLayout(LayoutType);
		pFrame->draw();
		pLayout->installFrame();
	}
private:
	FrameApi* pFrame;
	LayoutApi* pLayout;
};

int main() {
	GUIEngineer* pEng = new GUIEngineer;
	pEng->prepareDraw(1, 1);
	return 0;
}

这样的作法,应该告诉客户:

FrameType是用来选择Frame控件的类型

LayoutType是用来选择布局管理器的类型

如果客户这么做:

pEng->prepareDraw(1, 2);

则:

明显结果不适配。

为了避免这种结果,我们需要进行类似提取公因式的办法,来解决此类问题,把相像的关系进行提取,避免造成关系不适配的情况。

这里就引出抽象工厂的概念:

定义

  • 功能:
    • 为一系列相关对象或相互依赖的对象创建一个接口
    • 从某种意义上看,抽象工厂其实是一个产品系列,或者是产品簇
  • 实现:AbstractFactory为接口
  • 方法:
    • AbstractFactory定义产品所需接口,具体实现在实现类里面。
    • AbstractFactory定义的创建产品的方法可以看成是工厂方法,而这些工厂方法的具体实现就延迟到了具体的工厂里面,也就是说用工厂来实现抽象工厂
  • 切换产品簇:
    • AbstractFactory定义了一个产品簇,因此切换产品簇时提供不同的AbstractFactory就好了

我们将简单工厂替换为抽象工厂,也就是将产品替换为产品簇:

#include <iostream>
using namespace std;

class FrameApi {
public:
	virtual void draw() = 0;
protected:
	FrameApi() {}
};

class LayoutApi {
public:
	virtual void installFrame() = 0;
protected:
	LayoutApi() {}
};

//PC Frame
class ComputerFrame :public FrameApi {
public:
	ComputerFrame(int pins) :m_pins(pins) {}
	void draw() {
		cout << "现在是PC Frame,分辨率适用:" << m_pins << endl;
	}
private:
	int m_pins;
};
//Mobile Frame
class MobileFrame :public FrameApi {
public:
	MobileFrame(int pins) :m_pins() {}
	void draw() {
		cout << "现在是Mobile Frame,分辨率适用:" << m_pins << endl;
	}
private:
	int m_pins;
};

//高分辨率布局
class HighLayout :public LayoutApi {
public:
	HighLayout(int FrameAdapterPins) :m_FrameAdapterPins(FrameAdapterPins) {}
	void installFrame() {
		cout << "现在是在PC环境下使用高分辨率布局" << m_FrameAdapterPins << endl;
	}
private:
	int m_FrameAdapterPins;
};

//低分辨率布局
class LowLayout :public LayoutApi {
public:
	LowLayout(int FrameAdapterPins) :m_FrameAdapterPins(FrameAdapterPins) {}
	void installFrame() {
		cout << "现在是在Mobile环境下使用低分辨率布局" << m_FrameAdapterPins << endl;
	}
private:
	int m_FrameAdapterPins;
};




//AbstractFactory产品簇
class AbstractFactory {
public:
	virtual FrameApi* createFrameApi() = 0;
	virtual LayoutApi* createLayoutApi() = 0;
protected:
	AbstractFactory(){}
};
//产品簇1
class Schemal :public AbstractFactory {
public:
	FrameApi* createFrameApi() {
		return new ComputerFrame(1024);
	}
	LayoutApi* createLayoutApi() {
		return new HighLayout(1024);
	}
};
//产品簇2
class Schema2 :public AbstractFactory {
public:
	FrameApi* createFrameApi() {
		return new MobileFrame(1024);
	}
	LayoutApi* createLayoutApi() {
		return new LowLayout(1024);
	}
};

class AdanvancedGuiEngineer {
public:
	void prepareMaterials(AbstractFactory* pSchema) {
		this->pFrame = pSchema->createFrameApi();
		this->pLayout = pSchema->createLayoutApi();
		pFrame->draw();
		pLayout->installFrame();
	}
private:
	FrameApi* pFrame;
	LayoutApi* pLayout;
};

int main() {
	AdanvancedGuiEngineer* pEng = new AdanvancedGuiEngineer();
	pEng->prepareMaterials(new Schemal());
	return 0;
}

Nice!

其实就相当于:点套餐,这样就不会出现不适配的情况。

本质:选择产品簇的实现,优缺点

  • 优点:
    • 分离接口和实现
    • 切换产品簇变的容易
  • 缺点:
    • 不太容易扩展新产品
    • 容易造成类层次复杂

何时选用抽象工厂:强调一系列相关产品接口、联合使用它们的时候

 

抽象工厂模式的工程应用-控件式开发

  • 业务功能封装成控件
  • 微软有一个叫做asp.net的控件组,他认为对于一个Web应用来说,虽然搜索框、广告条、导航条、页面主题的设计和实现有很大差别,但是绝大多数的Web应用基本布局还是大致相同的。最后都可以组装成一个页面的过程也是大致相同的。
  • 这种具有同一属组的产品簇特别适合用抽象工厂进行装配

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值