C++设计模式---享元模式----浪费可耻,节俭光荣

概述

一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等问题。

想想我们编辑文档用的word,文档里文字很多都是重复的,我们不可能为每一个出现的汉字都创建独立的空间,这样代价太大,那么我们如何去避免系统中出现大量相同或相似的对象,同时又不影响客户端程序通过面向对象的方式对这些对象进行操作?

享元模式正为解决这一类问题而诞生。享元模式通过共享技术实现相同或相似对象的重用,在逻辑上每一个出现的字符都有一个对象与之对应,然而在物理上它们却共享同一个享元对象,这个对象可以出现在一个字符串的不同地方,相同的字符对象都指向同一个实例,在享元模式中,存储这些共享实例对象的地方称为享元池(Flyweight Pool)。我们可以针对每一个不同的字符创建一个享元对象,将其放在享元池中,需要时再从享元池取出。

实现策略

作用:运用共享技术有效地支持大量细粒度的对象。

内部状态intrinsic和外部状态extrinsic:

1)Flyweight模式中,最重要的是将对象分解成intrinsic和extrinsic两部分。
2)内部状态:在享元对象内部并且不会随环境改变而改变的共享部分,可以称为是享元对象的内部状态
3)外部状态:而随环境改变而改变的,取决于应用环境,或是实时数据,这些不可以共享的东西就是外部状态了。
4)内部状态和外部状态之间的区别:
  在Flyweight模式应用中,通常修改的是外部状态属性,而内部状态属性一般都是用于参考或计算时引用。
Flyweight执行时所需的状态必定是内部的或外部的。内部状态存储于ConcreteFlyweight对象之中;而外部状态则由Client对象存储或计算。当用户调用Flyweight对象的操作时,将该状态传递给它。

以文字处理软件为例:
  内部状态存储于flyweight中,它包含了独立于flyweight场景的信息,这些信息使得flyweight可以被共享。如字符代码,字符大小……
  外部状态取决于flyweight场景,并根据场景而变化,因此不可共享。用户对象负责在必要的时候将外部状态传递给flyweight,如字符位置,字符颜色……

组成

①Flyweight:

享元类的基类,定义一个接口,通过这个接口Flyweight可以接受并作用于外部状态。

②ConcreteFlyweight:

实现Flyweight接口, 并为内部状态( 如果有的话) 增加存储空间。ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的(intrinsic);即,它必须独立于ConcreteFlyweight对象的场景。

③UnsharedConcreteFlyweight:

并非所有的Flyweight子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,④UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。

FlyweightFactory:

1) 创建并管理Flyweight对象。
2)确保合理地共享Flyweight。当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)

⑥Client

1)维持一个对Flyweight的引用。
2)计算或存储一个(多个)Flyweight的外部状态。

UML



示例代码
// Flyweight.h
// Flyweight.h
#ifndef _FLYWEIGHT_H_
#define _FLYWEIGHT_H_

#include <string>
#include <vector>

using namespace std;

//基类,定义操作接口Operation
class Flyweight
{
public:
    //操作外部状态extrinsicState
    virtual void Operation(const string& extrinsicState) = 0;
    string GetIntrinsicState( );
    virtual ~Flyweight( );
protected:
    Flyweight(string intrinsicState);
private:
    
	// 内部状态,也可以放在ConcreteFlyweight中
    string _intrinsicState;
};


/*
ConcreteFlyweight:实现Flyweight接口, 并为内部状态( 如果有的话) 增加存储空间。
ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的(intrinsic);
即,它必须独立于ConcreteFlyweight对象的场景。
*/
class ConcreteFlyweight : public Flyweight
{
public:
    //实现接口函数
    virtual void Operation(const string& extrinsicState);
    ConcreteFlyweight(string intrinsicState);
    ~ConcreteFlyweight();
};


/*
UnsharedConcreteFlyweight:并非所有的Flyweight子类都需要被共享。
Flyweight接口使共享成为可能,但它并不强制共享。
在Flyweight对象结构的某些层次,
UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。
*/
class UnsharedConcreteFlyweight:public Flyweight
{
public:
    virtual void Operation(const string& extrinsicState);
    UnsharedConcreteFlyweight(string intrinsicState);
    ~UnsharedConcreteFlyweight();
};

class FlyweightFactory
{
public:
    FlyweightFactory();
    ~FlyweightFactory();
    //获得一个请求的Flyweight对象
    Flyweight* GetFlyweight(string key);
    //获取容器中存储的对象数量
    void GetFlyweightCount();
protected:
private:
    //保存内部状态对象的容器
    vector<Flyweight*> m_vecFly;
};
#endif

// Flyweight.cpp
// Flyweight.cpp
#include "Flyweight.h"
#include <iostream>

using namespace std;

Flyweight::Flyweight(string intrinsicState)
{
    this->_intrinsicState = intrinsicState;
}

Flyweight::~Flyweight()
{}

string Flyweight::GetIntrinsicState()
{
    return this->_intrinsicState;
}

ConcreteFlyweight::ConcreteFlyweight(string intrinsicState):Flyweight(intrinsicState)
{
}

ConcreteFlyweight::~ConcreteFlyweight()
{
}

void ConcreteFlyweight::Operation(const string& extrinsicState)
{
    cout << this->GetIntrinsicState() << endl;
    cout << extrinsicState << endl;
}

UnsharedConcreteFlyweight::UnsharedConcreteFlyweight(string intrinsicState):Flyweight(intrinsicState)
{
}

UnsharedConcreteFlyweight::~UnsharedConcreteFlyweight()
{
}

void UnsharedConcreteFlyweight::Operation(const string& extrinsicState)
{
    cout << "extrinsicState" << endl;
}

FlyweightFactory::FlyweightFactory()
{}

FlyweightFactory::~FlyweightFactory()
{}

//若该对象已存在,直接返回,否则新建一个对象,存入容器中,再返回
Flyweight* FlyweightFactory::GetFlyweight(string key)
{
    vector<Flyweight*>::iterator iter = this->m_vecFly.begin();
    for(;iter!= this->m_vecFly.end();iter++)
    {
        if((*iter)->GetIntrinsicState() == key)
        {
            return *iter;
        }
    }
    Flyweight* fly = new ConcreteFlyweight(key);
    this->m_vecFly.push_back(fly);
    return fly;
}

void FlyweightFactory::GetFlyweightCount()
{
    cout << this->m_vecFly.size() << endl;
}

main.cpp
#include "Flyweight.h"
#include <iostream>
#include <string>

using namespace std;

int main()
{
    //外部状态extrinsicState
    string extrinsicState = "ext";

    //工厂对象,工厂对象
    FlyweightFactory* fc = new FlyweightFactory();

    //向工厂申请一个Flyweight对象,且该对象的内部状态值为“hello”
    Flyweight* fly = fc->GetFlyweight("hello");

    Flyweight* fly1 = fc->GetFlyweight("hello");

    //应用外部状态
    fly->Operation(extrinsicState);

    fc->GetFlyweightCount();

    return 0;
}

Makefile
CC = gcc
CXX = g++

OBJECT = Flyweight.o main.o
TARGET = Flyweight.exe
INC = -I./


$(TARGET) : $(OBJECT)
	$(CXX) $(OBJECT) -o $(TARGET)

%.o : %.cpp
	$(CXX) -c $< -o $@ $(INC)


.PHONY : clean
clean :
	del $(OBJECT) $(TARGET)
	rm -rf $(OBJECT) $(TARGET)


参考:
另外一个围棋的例子:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值