设计模式【10】——享元模式( Flyweight 模式)


前言

创建对象的过程在面向对象系统的设计中是最经常用到的设计方法。但是,如果在设计过程中创建了太多的对象,会造成存储空间的巨大开销或者浪费。特别是对于大量轻量级(细粒度)的对象,比如在文档编辑器的设计过程中,我们如果为没有字母创建一个对象的话,系统可能会因为大量的对象而造成存储开销的浪费。例如一个字母“a”在文档中出现了100000 次,而实际上我们可以让这一万个字母“a”共享一个对象,当然因为在不同的位置可能字母“a”有不同的显示效果(例如字体和大小等设置不同),在这种情况我们可以为将对象的状态分为“外部状态”和“内部状态”,将可以被共享(不会变化)的状态作为内部状态存储在对象中,而外部对象(例如上面提到的字体、大小等)我们可以在适当的时候将外部对象最为参数传递给对象(例如在显示的时候,将字体、大小等信息传递给对象)。


一、享元模式( Flyweight 模式)

Flyweight 模式中存在类似 Factory 模式的对象构造工厂FlyweightFactory,当客户(Client)需要一个对象时候就会向 FlyweightFactory 发出请求对象的消息 GetFlyweight()消息,FlyweightFactory 拥有一个管理、存储对象的“仓库”(或者叫对象池,这里采用map实现,方便查找),GetFlyweight()消息会遍历对象池中的对象,如果已经存在则直接返回给 Client,否则创建一个新的对象返回给 Client。UML图如下:
Flyweight 模式示意图

二、具体源码

1.FlyWeight.h

代码如下(示例):

#ifndef _FLYWEIGHT_H_ 
#define _FLYWEIGHT_H_ 

#include <iostream>
#include <string> 

class Flyweight
{
public:

  virtual ~Flyweight();
  virtual void Operation(const std::string& extrinsicState);
  std::string GetIntrinsicState();

protected:
  Flyweight(std::string intrinsicState);
private:
  std::string _intrinsicState;
};

class ConcreteFlyweight :public Flyweight
{
public:

  ConcreteFlyweight(std::string intrinsicState);
  ~ConcreteFlyweight();

  //子类中实现接口,如字体“a”设置大小、颜色等
  void Operation(const std::string& extrinsicState);

protected:
private:

};
#endif //_FLYWEIGHT_H_

2.FlyWeight.cpp

代码如下(示例):

#include "Flyweight.h"

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

Flyweight::~Flyweight()
{
}

void Flyweight::Operation(const std::string& extrinsicState)
{
  this->_intrinsicState += extrinsicState;
}

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

ConcreteFlyweight::ConcreteFlyweight(std::string intrinsicState) :Flyweight(intrinsicState)
{
  std::cout << "ConcreteFlyweight Build....." << intrinsicState << std::endl;
}
ConcreteFlyweight::~ConcreteFlyweight()
{
}
void ConcreteFlyweight::Operation(const std::string& extrinsicState)
{
  std::cout << "ConcreteFlyweight:内蕴[" << this->GetIntrinsicState() << "] 外 蕴[" << extrinsicState << "]" << std::endl;
}

3.FlyWeightFactory.h

代码如下(示例):

#pragma once

#ifndef _FLYWEIGHTFACTORY_H_ 
#define _FLYWEIGHTFACTORY_H_ 

#include "Flyweight.h" 
#include <map> 
#include <cassert> 

class FlyweightFactory
{
public:

  FlyweightFactory();
  ~FlyweightFactory();
  Flyweight * GetFlyweight(const std::string& key);

protected:
private:
  //存储内部对象,采用map方便查找
  std::map<std::string,Flyweight*> _fly;
};
#endif //_FLYWEIGHTFACTORY_H_

4.FlyWeightFactory.cpp

代码如下(示例):

#include "FlyweightFactory.h" 

FlyweightFactory::FlyweightFactory()
{
}
FlyweightFactory::~FlyweightFactory()
{
  //注意析构函数需要将申请的内存进行销毁
  for (auto itor : _fly)
  {
    delete _fly[itor.first];
    _fly[itor.first] = nullptr;
  }
}

Flyweight* FlyweightFactory::GetFlyweight(const std::string& key)
{
  //若存在,在返回对象
  if (this->_fly.count(key) != 0)
    return this->_fly[key];
  //不存在时,常见新对象并返回
  else
  {
    Flyweight * fn = new ConcreteFlyweight(key);
    _fly[key]=fn;
    return fn;
  }
}

5.main.cpp

代码如下(示例):

#include "Flyweight.h" 
#include "FlyweightFactory.h" 

int main(int argc, char* argv[])
{
  FlyweightFactory* fc = new FlyweightFactory();
  Flyweight* fw1 = fc->GetFlyweight("hello");
  fw1->Operation("world!");

    Flyweight* fw2 = fc->GetFlyweight("Good morning!");
  Flyweight* fw3 = fc->GetFlyweight("hello");
  fw3->Operation("China!");

  return 0;
}

三、运行结果

Flyweight 模式运行结果如下:
 Flyweight 模式运行结果


总结

Flyweight 模式主要用于减少创建对象的数量,以减少内存占用和提高性能,属于结构型模式。好处是:减少了对象数量,使得相同对象或相似对象在内存中只保存一份,从而改善应用所需的对象结构的方式,同时内部状态与外部状态相对独立,而且不会影响其相互影响,从而使得内部对象可以在不同的环境中被共享。但是,它也会使得系统更加复杂,为了使对象可以共享,需要将一些状态外部化,这样使得程序的逻辑复杂化。


本文参考《设计模式精解-GoF 23 种设计模式解析附 C++实现源码》,对内容进行整理,方便大家学习。如想学习详细内容,请参考此书。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
享元设计模式Flyweight Design Pattern)是一种用于优化大量对象创建和使用的设计模式。在Android开发中,使用享元模式可以有效地减少内存消耗和提高性能。 在享元模式中,对象被分为两种状态:内部状态和外部状态。内部状态是不变的,可以被多个对象共享,而外部状态是可变的,每个对象都有自己的外部状态。 在Android中,典型的例子是使用Bitmap对象来显示图片。当需要显示多个相同的图片时,可以使用享元模式来共享已加载的Bitmap对象,而不是每次都创建新的Bitmap对象。 以下是一个简单的示例代码: ```java public class BitmapFactory { private Map<String, Bitmap> bitmapCache = new HashMap<>(); public Bitmap getBitmap(String path) { Bitmap bitmap = bitmapCache.get(path); if (bitmap == null) { // 如果缓存中没有该Bitmap对象,则创建新的Bitmap对象 bitmap = BitmapFactory.decodeFile(path); bitmapCache.put(path, bitmap); } return bitmap; } } ``` 在上面的示例中,`BitmapFactory` 类使用一个 `bitmapCache` Map 来缓存已加载的 Bitmap 对象。当需要获取 Bitmap 对象时,首先从缓存中查找,如果找到则返回缓存的对象,否则创建新的 Bitmap 对象并存入缓存。 通过使用享元模式,可以避免重复创建相同的 Bitmap 对象,从而减少内存消耗。这在需要频繁加载和显示大量图片的应用中非常有用。 需要注意的是,享元模式适用于有大量相似对象的情况,并且需要权衡共享对象和创建对象的开销。在某些情况下,过度使用享元模式可能会导致代码复杂化,降低可读性和可维护性。因此,在使用享元模式时应根据实际情况进行评估和折衷。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

希望早日退休的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值