博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式C++实现(8)——代理模式
阅读量:6093 次
发布时间:2019-06-20

本文共 3039 字,大约阅读时间需要 10 分钟。

hot3.png

软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运 用了面向对象编程语言的重要特性:封装、继承、多态,真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积累。最近看设计模式的书,对于每 个模式,用C++写了个小例子,加深一下理解。主要参考《大话设计模式》和《设计模式:可复用面向对象软件的基础》(DP)两本书。本文介绍代理模式的实 现。

        [DP]上的定义:为其他对象提供一种代理以控制对这个对象的访问。有四种常用的情况:(1)远程代理,(2)虚代理,(3)保护代理,(4)智能引用。本文主要介绍虚代理和智能引用两种情况。

       考虑一个可以在文档中嵌入图形对象的文档编辑器。有些图形对象的创建开 销很大。但是打开文档必须很迅速,因此我们在打开文档时应避免一次性创建所有开销很大的对象。这里就可以运用代理模式,在打开文档时,并不打开图形对象, 而是打开图形对象的代理以替代真实的图形。待到真正需要打开图形时,仍由代理负责打开。这是[DP]一书上的给的例子。下面给出代理模式的UML图。

       简单实现如下:

class Image{public:	Image(string name): m_imageName(name) {}	virtual ~Image() {}	virtual void Show() {}protected:	string m_imageName;};class BigImage: public Image{public:	BigImage(string name):Image(name) {}	~BigImage() {}	void Show() { cout<<"Show big image : "<
<
Show(); }};

         客户调用:

int main(){	Image *image = new BigImageProxy("proxy.jpg"); //代理	image->Show(); //需要时由代理负责打开	delete image;	return 0;}

         在这个例子属于虚代理的情况,下面给两个智能引用的例子。一个是C++中的auto_ptr,另一个是smart_ptr。自己实现了一下。先给出auto_ptr的代码实现:

template
class auto_ptr { public: explicit auto_ptr(T *p = 0): pointee(p) {} auto_ptr(auto_ptr
& rhs): pointee(rhs.release()) {} ~auto_ptr() { delete pointee; } auto_ptr
& operator=(auto_ptr
& rhs) { if (this != &rhs) reset(rhs.release()); return *this; } T& operator*() const { return *pointee; } T* operator->() const { return pointee; } T* get() const { return pointee; } T* release() { T *oldPointee = pointee; pointee = 0; return oldPointee; } void reset(T *p = 0) { if (pointee != p) { delete pointee; pointee = p; } } private: T *pointee; };

        阅读上面的代码,我们可以发现 auto_ptr 类就是一个代理,客户只需操作auto_prt的对象,而不需要与被代理的指针pointee打交道。auto_ptr 的好处在于为动态分配的对象提供 异常安全。因为它用一个对象存储需要被自动释放的资源,然后依靠对象的析构函数来释放资源。这样客户就不需要关注资源的释放,由auto_ptr 对象自动完成。实现中的一个关键就是重载了解引用操作符和箭头操作符,从而使得auto_ptr的使用与真实指针类似。

       我们知道C++中没有垃圾回收机制,可以通过智能指针来弥补,下面给出智能指针的一种实现,采用了引用计数的策略。

template 
class smart_ptr{public: smart_ptr(T *p = 0): pointee(p), count(new size_t(1)) { } //初始的计数值为1 smart_ptr(const smart_ptr &rhs): pointee(rhs.pointee), count(rhs.count) { ++*count; } //拷贝构造函数,计数加1 ~smart_ptr() { decr_count(); } //析构,计数减1,减到0时进行垃圾回收,即释放空间 smart_ptr& operator= (const smart_ptr& rhs) //重载赋值操作符 { //给自身赋值也对,因为如果自身赋值,计数器先减1,再加1,并未发生改变 ++*count; decr_count(); pointee = rhs.pointee; count = rhs.count; return *this; } //重载箭头操作符和解引用操作符,未提供指针的检查 T *operator->() { return pointee; } const T *operator->() const { return pointee; } T &operator*() { return *pointee; } const T &operator*() const { return *pointee; } size_t get_refcount() { return *count; } //获得引用计数器值private: T *pointee; //实际指针,被代理 size_t *count; //引用计数器 void decr_count() //计数器减1 { if(--*count == 0) { delete pointee; delete count; } }};

转载于:https://my.oschina.net/iamhere/blog/417590

你可能感兴趣的文章
烂泥:NFS做存储与KVM集成
查看>>
烂泥:puppet添加带密码的用户
查看>>
awk内建函数
查看>>
Nginx环境下隐藏Nginx的版本信息
查看>>
关于数据库的分库分表
查看>>
Docker容器之最小JDK基础镜像
查看>>
ext3grep恢复linux下误删除的文件
查看>>
Amazon SNS Mobile Push Notifications
查看>>
c语言判断平年/闰年
查看>>
支持双启动的PC平台Chrome OS版本问世
查看>>
崛起中的九大HTML5开发工具
查看>>
linux下svn命令使用大全:二
查看>>
ARp欺骗
查看>>
myeclipse10.0优化
查看>>
LVM
查看>>
mysql数据的binlog处理方法
查看>>
Centos7搭建yum本地源
查看>>
我的友情链接
查看>>
mysql 主从分离 读写分离(mysql-proxy)
查看>>
linux笔记 1-11-系统日志之时间同步
查看>>