享元模式思想  

  就以小时候导锅来说吧(导锅是我家乡的方言,就是用细沙把一个模型锅的形状拓下来,然后把铝水倒进模型中,就导好一个锅了。小时候很喜欢看的,可惜现在看不到了。上个图片回忆下)了解了这个过程后就知道,沙子、模型锅、都是可以一直使用的。而用做化铝水的物品是需要不同铝制品东西化生成。做这个生意的人不可能用一次沙子和模型锅就因为用过不用了。

  在代码的世界里,那些不变的类属性就像这些沙子和模型锅可以共享使用,而变化的类属性就像为导锅化铝水的铝制品一样是不同变化的。但实际上很多程序员就没有共享那些不变属性,而是生成一个类,就新建一个这样的可共享属性。就如同导锅用了一次的锅和沙子就弃之不用了,下次再用新的一样,多么可笑的事情啊,而享元模式就是为了阻止我们干这样可笑的蠢事而生的。

  

  来看下共享模式的定义:运用共享技术有效地支持大量细粒度的对象,达到节省内存的目的。咋一看不太明白这句话的意思,其实就是本文开篇描述的那个意思。

享元模式结构

模式参与成员:

  Flyweight:享元抽象接口

  FlyweightFactory:管理共享享元对象的缓存池。

  ConcreteFlyweight:可共享的类,里面存放着都是不会随着场景变化而变化的状态,同时介绍不可共享的状态的传入。

  Client:模拟试用享元对象的地方(对享元模式来说就是客户端)

例子

  为了更好的来理解享元模式,我们来举个例子。就以网店邮寄快递这个场景为例子展示此模式。

  一个快递对象都有哪些属性呢,来列举下。快递物品名称,价格,邮寄人,邮寄人电话,邮寄人地址,接收人姓名,接收人电话,接收人地址。既然要用享元模式了就要根据此模式的特征来分析一下,可共享(不变)状态和不可共享(随着不同包裹变化的)状态。

不变的状态有:邮寄人,邮寄人电话,邮寄人地址。我们把相同的物品共享一个对象的话,还有物品名称、价格。

不可共享的状态:接收人姓名,接收人电话,接收人地址。

分好这变化状态和不变状态以后,接下来就构建代码了。

享元抽象接口

 //抽象接口,相当于 Flyweight
public interface KuaiDi {
// jsr 接受不可共享部分
public void sendkd(Jiesr jsr);
}

实现接口的可共享类

 public class ConcreteKuaidi implements KuaiDi {

     private String kdName;
private String fsrName;
private String fsrPhone;
private String fsrAddress; public ConcreteKuaidi(String name,String fsrName,String fsrdh,String fsradrress){
this.kdName = name;
this.fsrName = fsrName;
this.fsrPhone = fsrdh;
this.fsrAddress = fsradrress;
} /* getter 和 setter 方法省略了 */ @Override
public void sendkd(Jiesr jsr) {
// TODO Auto-generated method stub
String msg = "邮寄"+ kdName +"给"+jsr.getJsrName()+"\n";
msg = msg + "接受人电话:"+jsr.getJsrPhone()+"\n";
msg = msg + "接受人地址:"+jsr.getAddress()+"\n";
msg = msg + "发送地址:"+fsrAddress+"\n";
System.out.println(msg);
// 打印类对象地址,更好的看出来类共享
System.out.println(this.toString());
System.out.println("------------------------------------");
} }

不可共享部分的类, 快递接收人

public class Jiesr {
private String jsrName;
private String jsrPhone;
private String Address; public String getJsrName() {
return jsrName;
} public String getJsrPhone() {
return jsrPhone;
} public String getAddress() {
return Address;
} public Jiesr(String jsrName,String jsrPhone,String Address){
this.jsrName = jsrName;
this.jsrPhone = jsrPhone;
this.Address = Address;
}
}

享元工厂,实现成为单例模式,是共享以前生成的对象,还是需要新建一个对象,由这儿决定。

 public class KudiFactory {
private static KudiFactory kudiFactory = new KudiFactory(); private KudiFactory(){} public static KudiFactory getInstance(){
return kudiFactory;
}
//用于存储 对象
private Map<String,KuaiDi> map = new HashMap<String,KuaiDi>(); // 类似工厂,存有对象池,在这儿生成对象
public KuaiDi getKuaidi(String name,String fsrName,String fsrdh,String fsradrress){
KuaiDi kd = map.get(name);
if(kd == null){
kd = new ConcreteKuaidi(name,fsrName,fsrdh,fsradrress);
map.put(name,kd);
}
return kd;
}
}

调用

public class Client {
public static void main(String[] args) { KudiFactory kk = KudiFactory.getInstance();
KuaiDi kuaidi1 = kk.getKuaidi("耐克运动鞋", "王小二耐克专营店", "", "汉东省京州市耐克园区10号");
Jiesr jsr1 = new Jiesr("张小四", "", "**省**市张小四村");
kuaidi1.sendkd(jsr1); KuaiDi kuaidi2 = kk.getKuaidi("耐克运动库", "王小二耐克专营店", "", "汉东省京州市耐克园区10号");
Jiesr jsr2 = new Jiesr("王小五", "", "**省**市张小5村");
kuaidi2.sendkd(jsr2); KuaiDi kuaidi3 = kk.getKuaidi("耐克运动鞋", "王小二耐克专营店", "", "汉东省京州市耐克园区10号");
Jiesr jsr3 = new Jiesr("李小六", "", "**省**市张小6村");
kuaidi3.sendkd(jsr3); KuaiDi kuaidi4 = kk.getKuaidi("耐克运动库", "王小二耐克专营店", "", "汉东省京州市耐克园区10号");
Jiesr jsr4 = new Jiesr("钱小七", "", "**省**市张小7村");
kuaidi4.sendkd(jsr4); KuaiDi kuaidi5 = kk.getKuaidi("耐克运动鞋", "王小二耐克专营店", "", "汉东省京州市耐克园区10号");
Jiesr jsr5 = new Jiesr("孙小八", "", "**省**市张小8村");
kuaidi5.sendkd(jsr5); }
} /*-------------------------------------执行结果-------------------------------*/
邮寄耐克运动鞋给张小四
接受人电话:
接受人地址:**省**市张小四村
发送地址:汉东省京州市耐克园区10号 example.ConcreteKuaidi@5994a1e9
------------------------------------
邮寄耐克运动库给王小五
接受人电话:
接受人地址:**省**市张小5村
发送地址:汉东省京州市耐克园区10号 example.ConcreteKuaidi@2d11f5f1
------------------------------------
邮寄耐克运动鞋给李小六
接受人电话:
接受人地址:**省**市张小6村
发送地址:汉东省京州市耐克园区10号 example.ConcreteKuaidi@5994a1e9
------------------------------------
邮寄耐克运动库给钱小七
接受人电话:
接受人地址:**省**市张小7村
发送地址:汉东省京州市耐克园区10号 example.ConcreteKuaidi@2d11f5f1
------------------------------------
邮寄耐克运动鞋给孙小八
接受人电话:
接受人地址:**省**市张小8村
发送地址:汉东省京州市耐克园区10号 example.ConcreteKuaidi@5994a1e9
------------------------------------

分析上述例子。首先看结果,通过打印的对象地址我们可以看出来,虽然邮寄了5个快递,但是由于共享的问题,实际上只是创建了两个对象。运行鞋共享的一个对象。而运动裤共享的一个。由于网点的快递量是很大的。如果这个耐克专卖店就买鞋和裤子,那么理论上鞋共享一个、裤子共享一个对象就够了。这样极大的节省了内存空间的开销。

  虽然另外建了一个不可共享的外部类,但是这个外部类都是很小的。共享对象节省的内存远远大于这个外部类占用内存。

  享元工厂一定要实现要用单例模式来实现。这样更能节省内存,提交效率。

分析享元模式

  享元模式其实是一个很简单的设计模式,他的重点在于分清内部状态、外部状态。内部状态:可共享内容,就是不会变化的内容;外部状态:随着应用场景的变化会变化的状态。内部状态是应用享元模式的基础,一个需要大量产生的对象类,可分离出来的内部状态越多,那么用享元模式的价值就越高;或者共享状态不多,但是可分离成内部状态的属性是一个非常多的内容,占用空间很大,这样使用享元模式的效果也很好。

  享元模式的缺点:由于把原来的大对象换成了多个小颗粒对象,而且加入了享元工厂这个类,所以系统变复杂了。

  线程安全问题,在设置共享对象的时候一定要注意共享的类是否够场景试用,如果并发太高,而共享的对象太少,就会造成线程安全问题。比如都是访问一个类了。就造成了数据错乱了。

复合享元模式

简单来说,就是享元对象在保存后,某种情景下需要的对象是已存在的两种或以上的不同享元对象组合而成的。这样就不要再去保存这个组合成的享元类了。需要的时候用组合生成即可。

享元模式的理解误区

在开始看享元模式的时候,我对内部状态和外部状态的理解不得其所。总觉得应该把不变的设成外部状态,变化的弄成内部。把分离出去的外部状态聚合到咱们的主对象里。这样在使用类的时候就可以复用不变的外部状态了。认真思考一下这样的设计很明显它没有起到享元模式共享类,节省内容的作用。

在反复看了例子以后才明白了享元模式类结构意图。

设计模式之(十二)享元模式(Flyweight)的更多相关文章

  1. 设计模式(十)享元模式Flyweight(结构型)

    设计模式(十)享元模式Flyweight(结构型) 说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释 ...

  2. C#设计模式之十二享元模式(Flyweight)【结构型】

    一.引言   今天我们要讲[结构型]设计模式的第六个模式,该模式是[享元模式],英文名称是:Flyweight Pattern.还是老套路,先从名字上来看看."享元"是不是可以这样 ...

  3. javascript设计模式学习之十二——享元模式

    一.享元模式的定义及使用场景 享元模式是为了解决性能问题而诞生的设计模式,这和大部分设计模式为了提高程序复用性的原因不太一样,如果系统中因为创建了大量类似对象而导致内存占用过高,享元模式就非常有用了. ...

  4. 二十四种设计模式:享元模式(Flyweight Pattern)

    享元模式(Flyweight Pattern) 介绍运用共享技术有效地支持大量细粒度的对象. 示例有一个Message实体类,某些对象对它的操作有Insert()和Get()方法,现在要运用共享技术支 ...

  5. 享元模式 FlyWeight 结构型 设计模式(十五)

    享元模式(FlyWeight)  “享”取“共享”之意,“元”取“单元”之意. 意图 运用共享技术,有效的支持大量细粒度的对象. 意图解析 面向对象的程序设计中,一切皆是对象,这也就意味着系统的运行将 ...

  6. 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern)

    原文:乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) 作者:weba ...

  7. 设计模式-11享元模式(Flyweight Pattern)

    1.模式动机 在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题.创建那么多的对象将会耗费很多的系统资源,它是系统性能提高的一个瓶颈. 享元模式就是把相同或相似对象的公共部分提取出 ...

  8. 设计模式系列之享元模式(Flyweight Pattern)——实现对象的复用

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  9. Java设计模式(十一) 享元模式

    原创文章,同步发自作者个人博客 http://www.jasongj.com/design_pattern/flyweight/.转载请注明出处 享元模式介绍 享元模式适用场景 面向对象技术可以很好的 ...

  10. Java设计模式(十二) 策略模式

    原创文章,同步发自作者个人博客,http://www.jasongj.com/design_pattern/strategy/ 策略模式介绍 策略模式定义 策略模式(Strategy Pattern) ...

随机推荐

  1. 9-剑指offer: 二进制中1的个数

    题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 代码 class Solution { public: int NumberOf1(int n) { if(n==0) re ...

  2. P4677 山区建小学|区间dp

    P4677 山区建小学 题目描述 政府在某山区修建了一条道路,恰好穿越总共nn个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di 为了提高山区 ...

  3. Hello,DTOS!(下)

    如何验证编写的主引导程序?解决方案设计:将汇编源码编译为二进制机器码(nasm)创建虚拟盘(bximage)将二进制代码写入虚拟盘起始位置(dd)在虚拟机中将虚拟盘作为启动盘执行(vmware) 就算 ...

  4. windows自动化测试环境搭建文档

    步骤如下: 1.搭建安卓环境,需要设置系统变量“ANDROID_HOME”. 2.安装Node.js http://www.nodejs.org/download/ 下载相关操作系统的版本 3.安装A ...

  5. 201871010107-公海瑜《面向对象程序设计(java)》第十六周学习总结

    201871010107-公海瑜<面向对象程序设计(java)>第十六周学习总结            项目                            内容   这个作业属于哪 ...

  6. 201871010135 张玉晶《面向对象程序设计(java)》第6-7周学习总结

    201871010135 张玉晶<面向对象程序设计(java)>第6-7周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ ...

  7. 基于Distiller的模型压缩工具简介

    Reference: https://github.com/NervanaSystems/distiller https://nervanasystems.github.io/distiller/in ...

  8. makfile通用版本

    DIR_INC = ./include DIR_SRC = ./src DIR_OBJ = ./obj DIR_BIN = ./bin LIBS += -Wl,-rpath=../lib/HCNetS ...

  9. 【洛谷】P4594 [COCI2011-2012#5] BLOKOVI

    本来已经有一个专门记录洛谷题目的博客了,但这个题之毒瘤...... 为你专门写一篇总行了吧...... 传送门 先说一句,这个题每次摆放都靠到最右边不一定是最优的 因为它可以这个亚子 就是说上面那个块 ...

  10. Golang(十一)TLS 相关知识(二)OpenSSL 生成证书

    0. 前言 接前一篇文章,上篇文章我们介绍了数字签名.数字证书等基本概念和原理 本篇我们尝试自己生成证书 参考文献:TLS完全指南(二):OpenSSL操作指南 1. OpenSSL 简介 OpenS ...