工厂模式:封装对象的创建(一、在基类中定义一个静态成员函数)
2015-12-07 10:59
549 查看
当我们发现需要添加新的类型到一个系统中时,最明智的首要步骤就是用多态机制为这些新类型创建一个共同的接口。
用这种方法可以将系统中多余的代码与新添加的特定类型的代码分开。新类型的添加并不会搅乱已存在的代码...或者至少看上去如此。
起初它似乎只需要在继承新类的地方修改代码,但这并非完全正确,仍须创建对象,在创建对象的地方必须指定要使用的准确的构造函数。
因此,如果创建对象的代码遍布整个应用的程序,在增加新类型时将会遇到同样的问题---------仍然必须找出代码中所有与新类型相关的地方。
这是由类的创建而不是类型的使用(类型的使用问题已经被多态机制解决了)而引起的。
解决该问题的方法就是强制用一个通用的工厂(factory)来创建对象,而不允许将创建对象的代码散布整个系统。
如果程序中所有的需要创建对象的代码都转到这个工厂(factory)执行,那么在新增加对象时所要做的全部工作就是只需要修改工厂。
这种设计就是工厂方法(Factory Method)模式的一种变体。
举个例子:(实现工厂模式的一种方法就是在基类中定义一个静态成员函数)
函数factory ()允许以一个参数来决定创建何种类型的Shape 在这里,参数类型为string 也可以是任何数据集 。
在添加新的Shape类型时,函数factory()是当前系统中唯一需要修改的代码。
(对象的初始化数据大概也可以由系统外获得。而不必像本例中来自硬编码数组。)
为了确保对象的创建只能发生在函数factory()中,
Shape的特定类型的构造函数被设为私有的,同时Shape被声明为友元类,因此factory()能够访问这些构造函数。
(也可以只将Shape::factory() 声明为友元函数,但是似乎声明整个基类为友元类也没什么大碍。)
这样的设计还有另外一个重要的含义——基类Shape现在必须了解每个派生类的细节——这是面向对象设计试图避免的一个性质,
对于结构框架或者任何类库来说都应该支持扩充,但是这样一来,系统很快就会变得笨拙,因为一旦新类型被加入到这种层次结构中,
基础类就必须更新,可以使用多态工厂(polymorphic factory)来避免这种循环依赖。
用这种方法可以将系统中多余的代码与新添加的特定类型的代码分开。新类型的添加并不会搅乱已存在的代码...或者至少看上去如此。
起初它似乎只需要在继承新类的地方修改代码,但这并非完全正确,仍须创建对象,在创建对象的地方必须指定要使用的准确的构造函数。
因此,如果创建对象的代码遍布整个应用的程序,在增加新类型时将会遇到同样的问题---------仍然必须找出代码中所有与新类型相关的地方。
这是由类的创建而不是类型的使用(类型的使用问题已经被多态机制解决了)而引起的。
解决该问题的方法就是强制用一个通用的工厂(factory)来创建对象,而不允许将创建对象的代码散布整个系统。
如果程序中所有的需要创建对象的代码都转到这个工厂(factory)执行,那么在新增加对象时所要做的全部工作就是只需要修改工厂。
这种设计就是工厂方法(Factory Method)模式的一种变体。
举个例子:(实现工厂模式的一种方法就是在基类中定义一个静态成员函数)
#include <stdexcept> #include <cstddef> #include <string> #include <vector> #include <algorithm> #include <iostream> using namespace std; template<class Seq> void purge(Seq& c) { typename Seq::iterator i; for(i = c.begin(); i != c.end(); ++i) { delete *i; *i = 0; } } // Iterator version: template<class InpIt> void purge(InpIt begin, InpIt end) { while(begin != end) { delete *begin; *begin = 0; ++begin; } }
class Shape { public: virtual void draw() = 0; virtual void erase() = 0; virtual ~Shape() {} class BadShapeCreation : public logic_error { public: BadShapeCreation(string type): logic_error("Cannot create type " + type) {} }; static Shape* factory(const string& type) throw(BadShapeCreation); }; class Circle : public Shape { Circle() {} // Private constructor friend class Shape; public: void draw() { cout << "Circle::draw" << endl; } void erase() { cout << "Circle::erase" << endl; } ~Circle() { cout << "Circle::~Circle" << endl; } };
class Square : public Shape { Square() {} friend class Shape; public: void draw() { cout << "Square::draw" << endl; } void erase() { cout << "Square::erase" << endl; } ~Square() { cout << "Square::~Square" << endl; } };
Shape* Shape::factory(const string& type) throw(Shape::BadShapeCreation) { if(type == "Circle") return new Circle; if(type == "Square") return new Square; throw BadShapeCreation(type); } char* sl[] = { "Circle", "Square", "Square","Circle", "Circle", "Circle", "Square"}; int main() { vector<Shape*> shapes; try { for(size_t i = 0; i < sizeof sl / sizeof sl[0]; i++) shapes.push_back(Shape::factory(sl[i])); } catch(Shape::BadShapeCreation e) { cout << e.what() << endl; purge(shapes); return -1; } for(size_t i = 0; i < shapes.size(); i++) { shapes[i]->draw(); shapes[i]->erase(); } purge(shapes); }
函数factory ()允许以一个参数来决定创建何种类型的Shape 在这里,参数类型为string 也可以是任何数据集 。
在添加新的Shape类型时,函数factory()是当前系统中唯一需要修改的代码。
(对象的初始化数据大概也可以由系统外获得。而不必像本例中来自硬编码数组。)
为了确保对象的创建只能发生在函数factory()中,
Shape的特定类型的构造函数被设为私有的,同时Shape被声明为友元类,因此factory()能够访问这些构造函数。
(也可以只将Shape::factory() 声明为友元函数,但是似乎声明整个基类为友元类也没什么大碍。)
这样的设计还有另外一个重要的含义——基类Shape现在必须了解每个派生类的细节——这是面向对象设计试图避免的一个性质,
对于结构框架或者任何类库来说都应该支持扩充,但是这样一来,系统很快就会变得笨拙,因为一旦新类型被加入到这种层次结构中,
基础类就必须更新,可以使用多态工厂(polymorphic factory)来避免这种循环依赖。
相关文章推荐
- Python动态类型的学习---引用的理解
- 土人系列AS入门教程 -- 对象篇
- C#托管堆对象实例包含内容分析
- C#实现获取不同对象中名称相同属性的方法
- javascript asp教程第十一课--Application 对象
- PowerShell中使用Out-String命令把对象转换成字符串输出的例子
- VBS教程:对象-正则表达式(RegExp)对象
- C#检查指定对象是否存在于ArrayList集合中的方法
- sql2008启动代理未将对象应用到实例解决方案
- C#编程自学之类和对象
- C++中对象的常引用、动态建立和释放相关知识讲解
- 介绍php设计模式中的工厂模式
- php中将一个对象保存到Session中的方法
- php对象和数组相互转换的方法
- PHP中把对象转换为关联数组代码分享
- C#写入对象或集合类型数据到xml文件的方法
- C#利用反射来判断对象是否包含某个属性的实现方法
- asp.net 简单工厂模式和工厂方法模式之论述
- ASP.NET中使用Application对象实现简单在线人数统计功能
- asp提示Server 对象 错误 ASP 0178 : 80070005