设计模式-抽象工厂模式

抽象工厂模式Abstract Factory):

    提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

  

    也就是说上面我有两个项目A和B,然后每个项目有两个子类1,2。如果是按照简单工厂或者是工厂方法的话,应该是一个大接口出来,然后细分四个子类,然后再在工厂里根据需求实例化哪个类(简单工厂),或者是直接定义工厂抽象接口,然后再分别实现一个工厂子类来负责实现具体的实体(工厂方法),而抽象工厂则的思路则是既然A和B都有方法1和2,那么我们就可以直接在工厂接口里把1和2写死,然后再细分出来两个产品A和B,这样当我们扩展一个产品C的时候(当然这里默认C也是有两个方法1和2),我们只要在对应的产品方面增加出来一个C,然后再在工厂方面增加一个子类就行了,这样的话,两个模块都是增加而不是修改,所以满足OCP,这就是抽象工厂的思路,抽象工厂看上去比较重,我们可以采取反射的技术去优化这个地方,当然简单工厂和工厂方法也可以采取反射的思路(它们两个用反射优化完就长得一样了)。下面通过例子来继续解释这个思路。

需求:有两个产品PC和Phone,同时每个产品都分为两个系统,WIndows和Linux,系统方面以后可能存在扩充,设计一个方便系统扩充的架构思路。通过抽象工厂思路实现上面要求:

UML结构如下



抽象工厂实现代码

#pragma once
#include <iostream>
using namespace std;

class CInterfaceOS
{
public:
	virtual void StartOs() = 0;
	virtual void CloseOs() = 0;
};

class CWindows : public CInterfaceOS
{
public:
	void StartOs()
	{
		cout<<"StartWindowsOs"<<endl;
	}
	void CloseOs()
	{
		cout<<"CloseWindowsOs"<<endl;
	}
};

class CLinux : public CInterfaceOS
{
public:
	void StartOs()
	{
		cout<<"StartLinuxOs"<<endl;
	}
	void CloseOs()
	{
		cout<<"CloseLinuxOs"<<endl;
	}
};

class CWindowsPc : public CWindows
{
public:
	void StartOs()
	{
		cout<<"WindowsPc:";
		CWindows::StartOs();
		
	}
	void CloseOs()
	{
		cout<<"WindowsPc:";
		CWindows::CloseOs();
	}
};

class CWindowsPhone : public CWindows
{
public:
	void StartOs()
	{
		cout<<"WindowsPhone:";
		CWindows::StartOs();

	}
	void CloseOs()
	{
		cout<<"WindowsPhone:";
		CWindows::CloseOs();
	}
};

class CLinuxPc : public CLinux
{
public:
	void StartOs()
	{
		cout<<"LinuxPc:";
		CLinux::StartOs();

	}
	void CloseOs()
	{
		cout<<"LinuxPc:";
		CLinux::CloseOs();
	}
};

class CLinuxPhone : public CLinux
{
public:
	void StartOs()
	{
		cout<<"LinuxPhone:";
		CLinux::StartOs();

	}
	void CloseOs()
	{
		cout<<"LinuxPhone:";
		CLinux::CloseOs();
	}
};

class CInterfaceFactory
{
public:
	virtual CInterfaceOS * CreatePcOs() = 0;
	virtual CInterfaceOS * CreatePhoneOs() = 0;
};


class CCreateFactoryWindows : public CInterfaceFactory
{
public:
	CInterfaceOS * CreatePcOs()
	{
		return new CWindowsPc();
	}
	CInterfaceOS * CreatePhoneOs()
	{
		return new CWindowsPhone();
	}
};


class CCreateFactoryLinux : public CInterfaceFactory
{
public:
	CInterfaceOS * CreatePcOs()
	{
		return new CLinuxPc();
	}
	CInterfaceOS * CreatePhoneOs()
	{
		return new CLinuxPhone();
	}
};

客户端调用代码

// TTT.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "AbstractFactory.h"
#include <iostream>
#include <windows.h>
using namespace std;

int main()
{
	CInterfaceFactory *pHashFactory[10] = {0};
	CInterfaceOS *pHashOs[10] = {0};
	int nHashFactoryId = -1 ,nHashOsId = -1;
	
	pHashFactory[++nHashFactoryId] = new CCreateFactoryWindows();
	pHashFactory[++nHashFactoryId] = new CCreateFactoryLinux();
	for(int i = 0 ;i <= nHashFactoryId ;i ++)
	{
		pHashOs[++nHashOsId] = pHashFactory[i]->CreatePcOs();
		pHashOs[++nHashOsId] = pHashFactory[i]->CreatePhoneOs();
	}
	for(int i = 0 ;i <= nHashOsId ;i ++)
	{
		pHashOs[i]->StartOs();
		pHashOs[i]->CloseOs();
	}

	for(int i = 0 ;i <= nHashFactoryId ;i ++)
	{
		delete pHashFactory[i];
	}
	for(int i = 0 ;i <= nHashOsId ;i ++)
	{
		delete pHashOs[i];
	}
	return 0;
}
结果



优化
    如上就是抽象工厂的基本实现,比较优雅,当扩充OS的时候是满足OCP的,当然上面的代码如果是扩充硬件,比如增加一个平板,那将是一个无比蛋疼的扩展,所以开发前自己衡量好。还有就是因为下面两个原因,在需要的时候有必要给抽象工厂进行一次优化:
  1.抽象工厂本身过于复杂,在方便维护扩展的同时也增加了维护的难度(有可能有人看上去会吃力或者蒙圈)。
  2.看上面,在客户端使用的时候客户端要了解所有工厂类,然后决定自己new哪个工厂,这样如果一个系统有100个地方用了一个数据库,那么我们100个地方都写了new但是如果换数据库的时候就算服务方面很容易就扩充了,但是客户端调用方面则要修改100个地方的new。
所以抽象工厂有必要进行优化(简单工厂和工厂方法一样可以优化),采取的方式就是利用反射技术(当然有的语言不支持这个技术),大体思路就是我们把工厂相关的东西全都去掉,比如上面那个就是去掉三个类 CCreateFactoryLinux,CCreateFactoryWindows,CInterfaceFactory。然后增加这个(反射):

const string g_Key = "A";
class CCreateBody
{
	CInterfaceOS * CreatePcOs()
	{
		 //根据相关语言进行反射(g_Key为key值)
		 //return new sg_Key();
	}
	CInterfaceOS * CreatePhoneOs()
	{
		//根据相关语言进行反射(g_Key为key值)
		//return new sg_Key();
	}
};


总结
    最大的好处便是易于交换产品系列,由于具体工厂类,在一个应用中只需要在吃实话的时候出现一次,也就使得改变一个应用的具体工厂变得非常容易,他只需要改变具体工厂即可使用不同的产品配置。可以这么理解,一个东西可以分成两部分,其中一部分是比较固定的,另一部分需要扩展,这个时候可以考虑使用抽象工厂。
    它让具体的创建实例过程与客户端分离,客户端通过他们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码中。
    缺点就是过于复杂,并且客户端使用的时候要知道太多的工厂类,耦合度太高,不过还好可以考虑反射优化。



原文地址:https://www.cnblogs.com/csnd/p/12062363.html