c++设计模式系列----factory模式
问题:
假设我们要开发一个游戏--打怪物,首先,游戏有分等级,假设有初级,中级两个个等级(就不用flappy bird模式了,那个比较特殊,对一个玩家来说是难以具有持久吸引力的!),不同的等级怪物也是不一样的,我们不妨假设初级为怪物A1, B1,中级为怪物A2,B2。如图所示:
设计:
那么根据面向对象思想,我们来考虑一下应该怎么设计程序结构,首先不同等级的怪物要由不同的对象来产生,即相当于不同等级的怪物也应该由不同类型的工厂来生产。但不同等级的怪物都是怪物,它们具有某些共同点,应该继承自同一个父怪物类。同样,不同等级的工厂也应该继承自同一个父工厂类。我们称这样的父工厂类和父怪物类为AbstractFactory和AbstractProduct。这个模式成为AbstractFactory模式。
AbstractFactory模式的典型结构图为:
其实这里我们还应该考虑的一个问题是我们为什么要增加一个AbstractFactory类,在factory模式中,是不需要AbstractFactory而是直接由factory类来生产product的,即如下的结构:
但我们从第二个图可以很容易看出,这里的factory只有一个,只能生产同一个等级的怪物。
首先,我们用factory的是为了解决两个问题:
1)、提高内聚和松耦合
2)、父类中无法知道要实例化哪个具体的子类(具体看下面)
这里引出了factory模式的两个重要功能:
1)定义创建对象的接口,封装了对象的创建;
2)使得具体化类的工作延迟到了子类中。
我们可以看出,第二个图的结构解决了第一个问题,即它使得我们能够规范的使用一个接口来初始化类,我们想象一下,为了达到多态,我们经常抽象出一个基类,然后很多不同的子类指向这个基类,这样我们在需要创建子类的对象的时候我们就必须知道具体的子类的名字,这样带来很多问题,如名称多而乱等,还有可拓展性问题。但有一个相同的接口的话,接口内部的修改不影响用户,可拓展性增强了,而且用户无需知道具体的子类的名字就可以创建对象了。
但是,第二个图的结构无法解决第二个问题。第二个图的模式只有一种基类。那么这时我们就要用到第一个图所显示的AbstractFactory 模式了。
AbstractFactory 模式通过将一组对象的额创建封装到一个用于创建对象的类(ConcreteFactory)中,这样,我们可以根据不同的ConcreteFactory类来实例化不同类型的子对象。并且,维护这样一个创建类总比维护n多相关对象的创建过程要简单的多。
下面我们来看看具体的代码实现:
//Product.h #ifndef PRODUCT_H
#define PRODUCT_H class AbstractProductA{
public:
virtual ~AbstractProductA();
protected:
AbstractProductA();
private:
}; class AbstractProductB
{
public:
virtual ~AbstractProductB();
protected:
AbstractProductB();
private:
}; class ProductA1: public AbstractProductA{
public:
ProductA1();
~ProductA1();
protected:
private:
}; class ProductA2:public AbstractProductA
{
public:
ProductA2();
~ProductA2();
protected:
private:
}; class ProductB1: public AbstractProductB{
public:
ProductB1();
~ProductB1();
protected:
private:
}; class ProductB2: public AbstractProductB{
public:
ProductB2();
~ProductB2();
protected:
private:
}; #endif
//Product.cpp #include "Product.h"
#include <iostream> using namespace std; AbstractProductA::AbstractProductA() {
cout << "AbstractProductA..." << endl;
} AbstractProductA::~AbstractProductA() {
cout << "~AbstractProductA..." << endl;
} AbstractProductB::AbstractProductB() {
cout << "AbstractProductB..." << endl;
} AbstractProductB::~AbstractProductB() {
cout << "~AbstractProductB..." << endl;
} ProductA1::ProductA1() {
cout << "ProductA1..." << endl;
}
ProductA1::~ProductA1() {
cout << "~ProductA1..." << endl;
} ProductA2::ProductA2() {
cout << "ProductA2..." << endl;
}
ProductA2::~ProductA2() {
cout << "~ProductA2..." << endl;
} ProductB1::ProductB1() {
cout << "ProductB1..." << endl;
}
ProductB1::~ProductB1() {
cout << "~ProductB1..." << endl;
} ProductB2::ProductB2() {
cout << "ProductB2..." << endl;
}
ProductB2::~ProductB2() {
cout << "~ProductB2..." << endl;
}
//AbstractFactory.h #ifndef ABSTRACTFACTORY_H
#define ABSTRACTFACTORY_H class AbstractProductA;
class AbstractProductB; class AbstractFactory{
public:
virtual ~AbstractFactory();
virtual AbstractProductA* CreateProductA() = ;
virtual AbstractProductB* CreateProductB() = ;
protected:
AbstractFactory();
private:
}; class ConcreteFactory1: public AbstractFactory{
public:
ConcreteFactory1();
~ConcreteFactory1();
AbstractProductA* CreateProductA();
AbstractProductB* CreateProductB();
protected:
private:
}; class ConcreteFactory2: public AbstractFactory{
public:
ConcreteFactory2();
~ConcreteFactory2();
AbstractProductA* CreateProductA();
AbstractProductB* CreateProductB();
protected:
private:
}; #endif
//AbstractFactory.cpp #include "AbstractFactory.h"
#include "Product.h"
#include <iostream> using namespace std; AbstractFactory::AbstractFactory() {
cout << "AbstractFactory..." << endl;
} AbstractFactory::~AbstractFactory() {
cout << "~AbstractFactory..." << endl;
} ConcreteFactory1::ConcreteFactory1() {
cout << "ConcreteFactory1..." << endl;
} ConcreteFactory1::~ConcreteFactory1() {
cout << "~ConcreteFactory1..." << endl;
} AbstractProductA* ConcreteFactory1::CreateProductA() {
return new ProductA1();
}
AbstractProductB* ConcreteFactory1::CreateProductB() {
return new ProductB1();
} ConcreteFactory2::ConcreteFactory2() {
cout << "ConcreteFactory2..." << endl;
} ConcreteFactory2::~ConcreteFactory2() {
cout << "~ConcreteFactory2..." << endl;
} AbstractProductA* ConcreteFactory2::CreateProductA() {
return new ProductA2();
}
AbstractProductB* ConcreteFactory2::CreateProductB() {
return new ProductB2();
}
//main.cpp #include"AbstractFactory.h"
#include<iostream> using namespace std; int main(int argc,char*argv[])
{
AbstractFactory* concretefactory1 = new ConcreteFactory1();
concretefactory1->CreateProductA();
concretefactory1->CreateProductB(); AbstractFactory* concretefactory2 = new ConcreteFactory2();
concretefactory2->CreateProductA();
concretefactory2->CreateProductB();
return ;
}
运行结果:
AbstractFactory...
ConcreteFactory1...
AbstractProductA...
ProductA1...
AbstractProductB...
ProductB1...
AbstractFactory...
ConcreteFactory2...
AbstractProductA...
ProductA2...
AbstractProductB...
ProductB2...
请按任意键继续. . .
c++设计模式系列----factory模式的更多相关文章
- 设计模式 - Abstract Factory模式(abstract factory pattern) 详细说明
Abstract Factory模式(abstract factory pattern) 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/ ...
- 设计模式之Factory模式(C++)
Factory模式具有两大重要的功能: (1).定义创建对象的接口,封装了对象的创建: (2).使具体化类工作延迟到了子类中. //Product.h #ifndef _PRODUCT_H_ #def ...
- PHP设计模式系列 - 外观模式
外观模式 通过在必需的逻辑和方法的集合前创建简单的外观接口,外观设计模式隐藏了调用对象的复杂性. 外观设计模式和建造者模式非常相似,建造者模式一般是简化对象的调用的复杂性,外观模式一般是简化含有很多逻 ...
- akka设计模式系列-While模式
While模式严格来说是while循环在Akka中的合理实现.while是开发过程中经常用到的语句之一,也是绝大部分编程语言都支持的语法.但while语句是一个循环,如果循环条件没有达到会一直执行wh ...
- PHP设计模式系列 - 工厂模式
工厂模式 提供获取某个对象实例的一个接口,同时使调用代码避免确定实例化基类的步骤. 工厂模式 实际上就是建立一个统一的类实例化的函数接口.统一调用,统一控制. 工厂模式是php项目开发中,最常用的设计 ...
- 设计模式之Factory模式 代码初见
ObjectFactory就是通过Factory建造一个Object,比如说DBConnectionFactory就是专门建造DBConnection的工厂 BuilderFactory就是通过Fac ...
- PHP设计模式系列 - 委托模式
委托模式 通过分配或委托其他对象,委托设计模式能够去除核心对象中的判决和复杂的功能性. 应用场景 设计了一个cd类,类中有mp3播放模式,和mp4播放模式 改进前,使用cd类的播放模式,需要在实例化的 ...
- c++设计模式系列----builder模式
看了好几处关于builder模式的书和博客,总感觉不是很清楚,感觉不少书上的说的也不是很准确.最后还是看回圣经<设计模式>.看了好久终于感觉明白了一点了. 意图: builder模式提出的 ...
- akka设计模式系列-Chain模式
链式调用在很多框架和系统中经常存在,算不得上是我自己总结的设计模式,此处只是简单介绍在Akka中的两种实现方式.我在这边博客中简化了链式调用的场景,简化后也更符合Akka的设计哲学. trait Ch ...
随机推荐
- usaco中遇到的问题
numbers are integers with unique digits 意思是数字中的每一个数字都是不一样的& 让一个图成为强连通图只需添加max(出度为0,入度为0)的点,然后如果图 ...
- POJ3630:Phone List——题解
http://poj.org/problem?id=3630 简单的trie树问题,先添加,然后每个跑一边看中途有没有被打上结束标记即可. #include<cstdio> #includ ...
- 洛谷 U32911 道路维护 解题报告
U32911 道路维护 题目背景 最近很多人投诉说C国的道路破损程度太大,以至于无法通行. C国的政府很重视这件事,但是最近财政有点紧,不可能将所有的道路都进行维护,所以他们决定按照下述方案进行维护. ...
- 【初级算法】6. 两个数组的交集 II
题目如下: 给定两个数组,写一个方法来计算它们的交集. 例如: 给定 nums1 = [, , , ], nums2 = [, ], 返回 [, ]. 注意: 输出结果中每个元素出现的次数,应与元素在 ...
- PhoneGap API介绍:File
本文将介绍PhoneGap API——File:通过JavaScript截获本地文件系统.File是用于读取.写入和浏览文件系统层次结构的PhoneGap API. 对象: DirectoryEntr ...
- Xcode 问题
问题: 昨天在写代码的时候,不知道修改了哪个地方,Xcode6突然犯病了,在当前项目下无法代码提示,但是在新建工程中没有任何问题,其中重装了Xcode6也没有把问题解决, 最终的解决办法是: 在fin ...
- Codeforces Round #398 (Div. 2) B,C
B. The Queue time limit per test 1 second memory limit per test 256 megabytes input standard input o ...
- C#中excel读取和写入
1.方法一:采用OleDB读取EXCEL文件: 把EXCEL文件当做一个数据源来进行数据的读取操作,实例如下: public DataSet ExcelToDS(string Path) { stri ...
- flask 自定义url转换器
from werkzeug.routing import BaseConverter app = Flask(__name__) class TeleConveter(BaseConverter): ...
- windows下用时间戳创建文件名
英文环境下: echo Archive_%date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.zip 中文: ...