享元模式

58次阅读

共计 1176 个字符,预计需要花费 3 分钟才能阅读完成。

简介

享元模式的英文名是 flyweight,在体育运动中指轻量级的,它使用共享支持大量细粒度对象的复用。享元模式避免了大量对象的创建,因此节省了很多内存空间。

UML 类图

示例

在 linux 下,可以创建软链接来实现多个链接,但只有一个文件实体。现在我们扮演操作系统的角色来管理这些软链接的文件。如果是复制的话和原型模式类似。
享元类,享元工厂类,flyweight.h

#ifndef FLYWEIGHT_H
#define FLYWEIGHT_H
#include <iostream>
#include <string>
#include <map>

using namespace std;
class CLink
{
public:
    CLink(const string& strName):m_strName(strName){};
    virtual void View(const string& strLinkName) = 0;
public:
    string m_strName;
    string m_strLinkName;
};

class CSoftFileLink:public CLink
{
public:
    CSoftFileLink(const string& strName):CLink(strName){}
    void View(const string& strLinkName)
    {
        m_strLinkName = strLinkName;
        cout<<strLinkName<<"->"<<m_strName<<endl;
    }
};



class CLinkFactory
{
public:
    static CLink* GetLink(const string& strName)
    {map<string, CLink*>::iterator iter = m_linkMap.find(strName);
        if(iter != m_linkMap.end())
        {return iter->second;}
        CLink* pLink = new CSoftFileLink(strName);
        m_linkMap.insert(make_pair(strName, pLink));
        return pLink;
    }
private:
    static map<string, CLink*> m_linkMap;
};
#endif

客户端调用,main.cpp

#include "flyweight.h"

map<string, CLink*> CLinkFactory::m_linkMap;
int main(int argc, char* argv[])
{
    CLinkFactory *pFactory = new CLinkFactory;
    CLink* pLink = pFactory->GetLink("test");
    pLink->View("testlink");
    return 0;
}

输出效果如下:

testlink->test

正文完
 0

享元模式

58次阅读

共计 2117 个字符,预计需要花费 6 分钟才能阅读完成。

享元模式
定义

提供了减少对象数量二改善应用所需的对象结构的方法
运用共享技术有效的支持大量粗粒度的对象。

用通俗的大白话来说就是减少对象的数量,提高对象的利用率,减少内存的使用,提高系统性能。
类型
创建型
适用场景

常常应用于系统底层的开发,一遍解决系统的性能问题。
系统中有大量的相似对象、需要使用缓冲池的场景。

优点

减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率。
减少内存之外的其他资源占用。(对象的创建是消耗其他的资源的)

缺点

关注内部 / 外部状态、关注线程安全问题。
系统逻辑的复杂化。(比如我们经常做一道面试题 Integer a=128;Integer b=128;a== b 是 true 还是 false,这里就有缓存的问题,后面我们再分析这个)

内部状态
在享对象类的内部,不会随着环境改变而改变的状态。
外部状态
记录在享元对象的外部,随着环境改变而改变。不可以共享的状态。
内部状态是享元对象的属性,不会随环境变化而变化的属性。外部状态我们打个比方就是在外部调用享元对象的方法时传过来一个 int 这个 int 为 1 时一种状态,为 2 时一种状态这就是外部状态。
我们来看看怎么实现。国际惯例假设一个应用场景,假设我们要做一个部门会议。
public interface Employee {
void report();
}
员工接口有个做报告方法。
public class Manager implements Employee {
@Override
public void report() {
System.out.println(reportContent);
}
private String title = “ 部门经理 ”;
private String department;
private String reportContent;

public void setReportContent(String reportContent) {
this.reportContent = reportContent;
}

public Manager(String department) {
this.department = department;
}

}
经理实现了员工接口。有三个属性,标题,部门,报告内容。
public class EmployeeFactory {
private static final Map<String,Employee> EMPLOYEE_MAP = new HashMap<String,Employee>();

public static Employee getManager(String department){
Manager manager = (Manager) EMPLOYEE_MAP.get(department);

if(manager == null){
manager = new Manager(department);
System.out.print(“ 创建部门经理:”+department);
String reportContent = department+” 部门汇报: 此次报告的主要内容是 ……”;
manager.setReportContent(reportContent);
System.out.println(” 创建报告:”+reportContent);
EMPLOYEE_MAP.put(department,manager);

}
return manager;
}

}
员工工厂,这里使用了容器单例模式。
public class FlyweightTest {
private static final String departments[] = {“RD”,”QA”,”PM”,”BD”};

public static void main(String[] args) {
for(int i=0; i<10; i++){
String department = departments[(int)(Math.random() * departments.length)];
Manager manager = (Manager) EmployeeFactory.getManager(department);
manager.report();
}
}
}
这里我们定义了一个部门列表,然后随机的使用其中一个部门去去执行报告操作。
创建部门经理:RD 创建报告:RD 部门汇报: 此次报告的主要内容是 ……
RD 部门汇报: 此次报告的主要内容是 ……
创建部门经理:PM 创建报告:PM 部门汇报: 此次报告的主要内容是 ……
PM 部门汇报: 此次报告的主要内容是 ……
RD 部门汇报: 此次报告的主要内容是 ……
创建部门经理:QA 创建报告:QA 部门汇报: 此次报告的主要内容是 ……
QA 部门汇报: 此次报告的主要内容是 ……
创建部门经理:BD 创建报告:BD 部门汇报: 此次报告的主要内容是 ……
BD 部门汇报: 此次报告的主要内容是 ……
RD 部门汇报: 此次报告的主要内容是 ……
RD 部门汇报: 此次报告的主要内容是 ……
PM 部门汇报: 此次报告的主要内容是 ……
QA 部门汇报: 此次报告的主要内容是 ……
BD 部门汇报: 此次报告的主要内容是 ……

正文完
 0