问题描述

假设我们要开发一款游戏, 当然为了吸引更多的人玩, 游戏难度不能太大(让大家都没有信心了,估计游戏也就没有前途了),但是也不能太简单(没有挑战性也不符合玩家的心理)。于是我们就可以采用这样一种处理策略: 为游戏设立等级,初级、中级、高级甚至有BT 级。 假设也是过关的游戏, 每个关卡都有一些怪物( monster) 守着, 玩家要把这些怪物干掉才可以过关。 作为开发者, 我们就不得不创建怪物的类, 然后初级怪物、 中级怪物等都继承自怪物类(当然不同种类的则需要另创建类,但是模式相同)。在每个关卡, 我们都要创建怪物的实例,例如初级就创建初级怪物( 有很多种类)、中级创建中级怪物等。可以想象在这个系统中, 将会有成千上万的怪物实例要创建, 问题是还要保证创建的时候不会出错:初级不能创建 BT 级的怪物(玩家就郁闷了,玩家一郁闷,游戏也就挂挂了),反之也不可以。

AbstractFactory 模式就是用来解决这类问题的:要创建一组相关或者相互依赖的对象。

UML类图

其关键就是将这一组对象的创建封装到一个用于创建对象的类( ConcreteFactory)中, 维护这样一个创建类总比维护 n 多相关对象的创建过程要简单的多

适用场合

工厂方法模式适用于产品种类结构单一的场合,为一类产品提供创建的接口;而抽象工厂方法适用于产品种类结构多的场合,主要用于创建一组(有多个种类)相关的产品,为它们提供创建的接口;就是当具有多个抽象角色时,抽象工厂便可以派上用场。

代码实现

#include <iostream>
#include <string>
using namespace std; class IUser
{
public:
virtual void getUser() = 0;
virtual void setUser() = 0;
}; class SqlUser :public IUser
{
public:
void getUser()
{
cout << "在sql中返回user" << endl;
}
void setUser()
{
cout << "在sql中设置user" << endl;
}
}; class AccessUser :public IUser
{
public:
void getUser()
{
cout << "在Access中返回user" << endl;
}
void setUser()
{
cout << "在Access中设置user" << endl;
}
}; class IDepartment
{
public:
virtual void getDepartment() = 0;
virtual void setDepartment() = 0;
}; class SqlDepartment :public IDepartment
{
public:
void getDepartment()
{
cout << "在sql中返回Department" << endl;
}
void setDepartment()
{
cout << "在sql中设置Department" << endl;
}
}; class AccessDepartment :public IDepartment
{
public:
void getDepartment()
{
cout << "在Access中返回Department" << endl;
}
void setDepartment()
{
cout << "在Access中设置Department" << endl;
}
}; class IFactory
{
public:
virtual IUser *createUser() = 0;
virtual IDepartment *createDepartment() = 0;
}; class SqlFactory :public IFactory
{
public:
IUser *createUser()
{
return new SqlUser();
}
IDepartment *createDepartment()
{
return new SqlDepartment();
}
}; class AccessFactory :public IFactory
{
public:
IUser *createUser()
{
return new AccessUser();
}
IDepartment *createDepartment()
{
return new AccessDepartment();
}
}; /*************************************************************/ class DataAccess
{
private:
static string db;
//string db="access";
public:
static IUser *createUser()
{
if (db == "access")
{
return new AccessUser();
}
else if (db == "sql")
{
return new SqlUser();
}
}
static IDepartment *createDepartment()
{
if (db == "access")
{
return new AccessDepartment();
}
else if (db == "sql")
{
return new SqlDepartment();
}
}
};
string DataAccess::db = "sql"; /*************************************************************/ int main()
{
//IFactory *factory=new SqlFactory();
IFactory *factory;
IUser *user;
IDepartment *department; factory = new AccessFactory();
user = factory->createUser();
department = factory->createDepartment(); user->getUser();
user->setUser();
department->getDepartment();
department->setDepartment(); user = DataAccess::createUser();
department = DataAccess::createDepartment(); user->getUser();
user->setUser();
department->getDepartment();
department->setDepartment(); return 0;

运行结果:


抽象工厂模式的优缺点

优点:(1)易于切换产品系列,由于具体工厂类在一个应用中只需要在初始化的时候出现一次,使得改变具体工厂非常容易。(2)具体的创建实例过程与客户端分离,客户端通过他们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码中。---充分运用了开放封闭原则和依赖倒转原则。

缺点:(2)根据上例,抽象工厂模式可以很方便地切换两个数据库访问的代码,但是如果你的需求来自增加功能,比如增加项目表Project,就至少需要增加三个雷,IProject、SqlserverProject、AccessProject,而且还要更改IFactory、SqlserverFactory和AccessFactory才行。

优化

(1)用简单工厂来改进抽象工厂

参考文献:

《C++设计模式》

《大话设计模式》

可推荐博客:C++设计模式——抽象工厂模式

c++实现反射

C++实现反射机制

 

设计模式之抽象工厂模式(附带类似反射功能的实现/c++)的更多相关文章

  1. 设计模式:抽象工厂模式(Abstract Factory)

    定   义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 结构图: 示例结构图: 实体类: class User { public int Id { get; set; } p ...

  2. 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern)

    原文:乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factor ...

  3. 桥接模式及C++实现 C++设计模式-AbstractFactory抽象工厂模式

    桥接模式及C++实现 桥接模式 先说说桥接模式的定义:将抽象化(Abstraction)与实现化(Implementation)分离,使得二者可以独立地变化. 桥接模式号称设计模式中最难理解的模式之一 ...

  4. Java 设计模式之抽象工厂模式(三)

    原文地址:Java 设计模式之抽象工厂模式(三) 博客地址:http://www.extlight.com 一.前言 上篇文章 <Java 设计模式之工厂模式(二)>,介绍了简单工厂模式和 ...

  5. 【设计模式】抽象工厂模式 Abstract Factory Pattern

    简单工厂模式是一个工厂类根据工厂方法的参数创建不出不同的产品, 工厂方法模式是每一个产品都有一个一一对应的工厂负责创建该产品.那么今天要讲的抽象工厂模式是一个工厂能够产生关联的一系列产品.抽象工厂模式 ...

  6. java设计模式之抽象工厂模式

    上一篇文章(http://www.cnblogs.com/liaoweipeng/p/5768197.html)讲了简单工厂模式,但是简单工厂模式存在一定的问题,如果想要拓展程序,必须对工厂类进行修改 ...

  7. php设计模式之抽象工厂模式

    之前总结了一下工厂模式,其实准确地说是简单 工厂模式,在它的基础上再进行抽象就可以得到一种新的模式:抽象工厂模式. 专业一点的定义为: 抽象工厂模式(Abstact Factory)是一种常见的软件设 ...

  8. (@WhiteTaken)设计模式学习——抽象工厂模式

    抽象工厂模式,可以向客户端提供一个接口,而客户端不用指定具体的类型创建对象,却能够创建多个产品族(一类具有共性产品,如地域等)的对象. 下面直接上代码. 1.苹果需要实现水果的接口,而苹果可以有北方的 ...

  9. 再起航,我的学习笔记之JavaScript设计模式06(抽象工厂模式)

    我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 前两 ...

随机推荐

  1. ethereum/EIPs-607 Hardfork Meta: Spurious Dragon硬分叉相关

    eip title author type status created requires 607 Hardfork Meta: Spurious Dragon Alex Beregszaszi Me ...

  2. 表情存储异常--mybatis抛出异常(java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x94' for column 'name' at row 1)

    文章参考 https://blog.csdn.net/junsure2012/article/details/42171035 https://www.cnblogs.com/WangYunShuai ...

  3. 深入浅出的webpack构建工具---DevServer配置项(二)

    深入浅出的webpack构建工具---DevServer配置项(二) 阅读目录 DevServer配置项 1. contentBase 2. port 3. host 4. headers 5. hi ...

  4. AI 信息论

    信息论,主要用于量化信息. 事件发生的概率越大,包含的信息就越少.例如“太阳从东边升起”,信息量就很少. 1.自信息(self-information) 两个独立事件发生所包含的信息,等于各自发生包含 ...

  5. 9、链表 & 状态机 & 多线程

    链表的引入 从数组的缺陷说起 数组有2个缺陷:一个是数组中所有元素的类型必须一致:第二个是数组的元素个数必须事先制定并且一旦指定之后不能更改. 如何解决数组的2个缺陷:数组的第一个缺陷靠结构体去解决. ...

  6. click事件和mousedown、mouseup事件

    点击select标签元素的时候,会弹出下拉.然而当option中没有元素时,就不希望弹出下拉(比如在某些浏览器中,点击select会默认出一个罩层效果,而此时没有数据选择的话,弹出比较不友好). 首先 ...

  7. Codeforces round 1098

    Div1 530 感受到被Div1支配的恐惧了.jpg 真·一个题都不会.jpg(虽然T1是我智障 感受到被构造题支配的恐惧了.jpg A 直接树上贪心就行,是我写错了.jpg B 这个构造超级神仙有 ...

  8. 实现Repeater控件的记录单选(二)

    前一篇<实现Repeater控件的记录单选>http://www.cnblogs.com/insus/p/7426334.html 虽然可以实现对Repeater控件的记录进行单选,但是, ...

  9. IOC框架之 Unity 入门

    十年河东,十年河西,莫欺少年穷 学无止境,精益求精 Unity是什么? Unity是patterns & practices团队开发的一个轻量级.可扩展的依赖注入容器,具有如下的特性: 1. ...

  10. vue-cli 3.0 路由懒加载

    当打包构建应用时,Javascript 包会变得非常大,影响页面加载.如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了. 1. 安装 synta ...