写在模式学习之前

什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式;每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案;当我们碰到模式所描述的问题,就可以直接用相应的解决方法去解决这个问题,这就是设计模式。

设计模式就是抽象出来的东西,它不是学出来的,是用出来的;或许你根本不知道任何模式,不考虑任何模式,却写着最优秀的代码,即使以“模式专家”的角度来看,都是最佳的设计,不得不说是“最佳的模式实践”,这是因为你积累了很多的实践经验,知道“在什么场合代码应该怎么写”,这本身就是设计模式。

有人说:“水平没到,学也白学,水平到了,无师自通”。诚然,模式背熟,依然可能写不出好代码,更别说设计出好框架;OOP理解及实践经验到达一定水平,同时也意味着总结了很多好的设计经验,但"无师自通",却也未必尽然,或者可以说,恰恰是在水平和经验的基础上,到了该系统的学习一下“模式”的时候了,学习一下专家总结的结果,印证一下自己的不足,对于提高水平还是很有帮助的。

本系列的设计模式学习笔记,实际是对于《Java与模式》这本书的学习记录。

享元模式的定义

享元模式以共享的方式高效地支持大量的细粒度对象。

享元对象能做到共享的关键是区分内部状态(Internal State)和外部状态(External State)。

一个内部状态是存储在享元对象内部的,并且是不会随环境改变而有所不同的。因此,一个享元可以具有内部状态并可以共享。

一个外部状态是随环境改变而改变的、不可以共享的状态。享元对象的外部状态必须由客户端保存,并在享元对象创建之后,在需要使用的时候再传入到享元对象内部。

外部状态不可以影响享元对象的内部状态。它们是相互独立的。

分类:

根据所涉及的享元对象的内部表象,享元模式可以分为单纯享元模式和复合享元模式。

应用场景:

享元模式在编辑器系统中大量使用。比如,用来将每一个字母做成一个享元对象,提供多种字体。

在Java语言中,String也使用了享元模式。在JVM内部,String对象是共享的,如果两个String对象所包含的字符串相同,JVM实际只创建了一个String对象提供给两个引用,从而实现了String对象的共享。在堆内存中,这两个String对象的地址;以及栈内存中,这两个String对象引用的地址,都是完全一致的。String的intern()方法给出这个字符串在共享池中的唯一实例。

如下可证:

String a="123";String b = "123";则a==b和a.equals(b)都是成立的;当然如果我们强制new新的堆内存,则不一致,比如String c = new String("123");则a==c是不成立的,但是a.equals(c)是成立的,说明a和c所的代表的值相等,但是a和c指向不同的栈地址空间。

单纯享元模式

结构图

所涉及的角色

(1)抽象享元(Flyweight)角色:此角色是所有的具体享元角色的超类,为这些类规定出需要实现的公共接口。那些需要外部状态的操作可以通过调研商业方法以参数形式传入。

(2)具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定的接口。如果有内部状态的话,必须负责为内部状态提供存储空间。享元对象的内部状态必须与对象所处的周围环境无关,从而使得享元对象 可以在系统内共享。

(3)享元工厂(FlyweightFactory)角色:负责创建和管理享元角色。享元工厂必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象时,享元工厂角色会检查系统中是否已经有一个符合要求的享元对象。如果有,就提供这个已有的享元对象;如果没有,就创建一个享元对象。

(4)客户端(Client)角色: 客户单角色需要维护一个对所有享元对象的引用,需要自行存储所有享元对象的外部状态。

代码实现

import java.util.*;
abstract class Flyweight
{//一个示意性的方法,参数state是外部状态public abstract void operation(String state);
}
class ConcreteFlyweight extends Flyweight
{private Character intrinsicState = null;//构造函数,内部状态作为参数传入public ConcreteFlyweight(Character state){this.intrinsicState = state;}//外部状态作为参数传入,改变方法的行为,但不改变对象的内部状态public void operation(String state){System.out.println("Intrinsic State = " + intrinsicState + ",Extrinsic State = " + state);}
}
class FlyweightFactory
{private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>();private Flyweight lnkFlyweight;public FlyweightFactory() {}public Flyweight factory(Character state){if(files.containsKey(state)){return files.get(state);} else{Flyweight fly = new ConcreteFlyweight(state);files.put(state,fly);return fly;} }//辅助方法public void checkFlyweight(){Flyweight fly;int i = 0;System.out.println("\n======checkFlyweight()======begin");for(Iterator it = files.entrySet().iterator();it.hasNext();){Map.Entry e = (Map.Entry)it.next();System.out.println("Item " + (++i) + ":" + e.getKey());}System.out.println("======checkFlyweight()======end");}
}
class Client
{public static void main(String[] args){//创建一个享元工厂对象FlyweightFactory factory = new FlyweightFactory();//向享元工厂对象请求一个内部状态为'a'的享元对象Flyweight fly = factory.factory(new Character('a'));//以参数方式传入一个外部状态fly.operation("First Call");//向享元工厂对象请求一个内部状态为'b'的享元对象fly = factory.factory(new Character('b'));//以参数方式传入一个外部状态fly.operation("Second Call");//向享元工厂对象请求一个内部状态为'a'的享元对象fly = factory.factory(new Character('a'));//以参数方式传入一个外部状态fly.operation("Third Call");//以上代码,虽然申请了3个享元对象,但是实际上只创建了两个,这就是共享的含义。//我们检查一下一个有几个对象factory.checkFlyweight();}
}

系统往往只需要一个享元工厂的实例,所以享元工厂可以设计成单例模式。

复合享元模式

结构图

所涉及的角色

(1)抽象享元(Flyweight)角色:此角色是所有具体享元类的超类,为这些类规定需要实现的公共接口。那些需要外部状态的操作可以通过方法的参数传入。抽象享元的接口使得享元共享成为可能,但是并不强制子类实行共享,因此并非所有的享元对象都是可以共享的。

(2)具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定的接口。如果有内部状态的话,必须负责为内部状态提供存储空间。享元对象的内部状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。有时候具体享元角色又叫做单纯具体享元角色,因为复合享元角色是由单纯具体享元角色通过复合而成的。

(3)复合享元(UnsharableFlyweight)角色:复合享元角色所代表的对象是不可以共享的,但是一个复合享元对象可以分解成为多个本身是单纯享元对象的组合。复合享元角色又称作不可共享的享元对象。

(4)享元工厂(FlyweightFactory)角色:享元工厂负责创建和管理享元对象。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象请求一个享元对象时,享元工厂角色检查是否已有一个符合要求的享元对象,如果有,则提供,如果没有,则创建。

(5)客户端(Client)角色: 客户单角色需要维护一个对所有享元对象的引用,需要自行存储所有享元对象的外部状态。

代理实例

import java.util.*;
abstract class Flyweight
{//一个示意性的方法,参数state是外部状态public abstract void operation(String state);
}
class ConcreteFlyweight extends Flyweight
{private Character intrinsicState = null;//构造函数,内部状态作为参数传入public ConcreteFlyweight(Character state){this.intrinsicState = state;}//外部状态作为参数传入,改变方法的行为,但不改变对象的内部状态public void operation(String state){System.out.println("Intrinsic State = " + intrinsicState + ",Extrinsic State = " + state);}
}
class ConcreteCompositeFlyweight extends Flyweight
{private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>(10);private Flyweight flyweight;public ConcreteCompositeFlyweight() {}public void add(Character key,Flyweight fly){files.put(key,fly);}public void operation(String extrinsicState){Flyweight fly = null;for(Iterator it = files.entrySet().iterator();it.hasNext();){Map.Entry e = (Map.Entry)it.next();fly = (Flyweight)e.getValue();fly.operation(extrinsicState);}}
}
class FlyweightFactory
{private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>();private Flyweight lnkFlyweight;public FlyweightFactory() {}public Flyweight factory(Character state){if(files.containsKey(state)){return files.get(state);} else{Flyweight fly = new ConcreteFlyweight(state);files.put(state,fly);return fly;} }//符合享元工厂方法,一般传入一个聚集对象,这里换入String,因为可以分解成Characterpublic Flyweight factory(String compositeState){ConcreteCompositeFlyweight compositeFly = new ConcreteCompositeFlyweight();int length = compositeState.length();Character state = null;for(int i=0;i<length;i++){state = new Character(compositeState.charAt(i));System.out.println("factory(" + state + ")");compositeFly.add(state,this.factory(state));}return compositeFly;}//辅助方法public void checkFlyweight(){Flyweight fly;int i = 0;System.out.println("\n======checkFlyweight()======begin");for(Iterator it = files.entrySet().iterator();it.hasNext();){Map.Entry e = (Map.Entry)it.next();System.out.println("Item " + (++i) + ":" + e.getKey());}System.out.println("======checkFlyweight()======end");}
}
class Client
{public static void main(String[] args){//创建一个享元工厂对象FlyweightFactory factory = new FlyweightFactory();//通过享元工厂对象创建一个具有某个组合状态的符合享元Flyweight fly = factory.factory("bcb");//以参数方式传入一个外部状态fly.operation("Composite Call");//以上代码,虽然申请了3个享元对象,但是实际上只创建了两个,这就是共享的含义。//我们检查一下一个有几个对象factory.checkFlyweight();}
}

通过以上代码可以看到,客户对象向享元工厂申请了一个内部状态为"bcb",外部状态为"Composite Call"的 享元对象。调用享元工厂的 辅助方法factory.checkFlyweight(),可以看到系统一共创建了两个单纯享元对象,分别对应"b"和"c"两种内部状态。

使用场景

当以下所有的条件都满足时,可以考虑使用享元模式:

(1)一个系统有大量的对象。

(2)这些对象耗费大量的内存。

(3)这些对象的状态中的大部分都可以外部化。

(4)这些对象可以按照内部状态分成很多的组,当把外部状态从对象中剔除时,每一个组都可以仅用一个对象代替。

(5)软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。

满足以上条件的系统可以使用享元模式。但是同时要注意,享元模式需要维护一个记录了系统已有的所有享元的表,而这需要耗费资源,因此,只有在有足够多的享元实例可供共享时才值得使用享元模式。

享元模式的优点和缺点

享元模式不是一个常见的模式,享元模式的优点在于它大幅度地降低内存中对象的数量。但是,做到这一点代价也是很高的:

(1)享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。

(2)享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。

在实际的工作过程中,个人还想不起来哪个项目真正使用过享元模式。

结构模式(Structural Pattern)小结

结构模式(Structural Pattern)一共有七种,分别是:适配器模式、装饰模式、合成模式、代理模式、享元模式、门面模式、桥梁模式。

大致总结如下:

  最大特点 典型应用
适配器模式 利用对象的功能,并转换其接口 日常工作,入目尽是适配器,DAO适配,Cache功能适配,等等
装饰模式 对象层面的功能增强,接口不变 Java I/O类库的设计
合成模式 树枝、叶子同样对待 分类树、权限树等
代理模式 代表人 WebService 的本地代理,权限访问代理,引用计数代理等
享元模式 共享对象,减小内存占用 编译器系统,Java String
门面模式 统一对外接口,方便调用 基于SOA框架编程中,不同系统之间的接口
桥梁模式 解耦 大多数的驱动器,包括JDBC Driver

设计模式学习笔记--享元(Flyweight)模式相关推荐

  1. 设计模式学习笔记——享元(Flyweight)模式

    设计模式学习笔记--享元(Flyweight)模式 @(设计模式)[设计模式, 享元模式, flyweight] 设计模式学习笔记享元Flyweight模式 基本介绍 享元案例 类图 实现代码 Big ...

  2. 设计模式学习笔记——中介者(Mediator)模式

    设计模式学习笔记--中介者(Mediator)模式 @(设计模式)[设计模式, 中介者模式, Mediator] 设计模式学习笔记中介者Mediator模式 基本介绍 中介者案例 类图 实现代码 Me ...

  3. 设计模式学习笔记——单例(Singleton)模式

    设计模式学习笔记--单例(Singleton)模式 @(设计模式)[设计模式, 单例模式, Singleton, 懒汉式, 饿汉式] 设计模式学习笔记单例Singleton模式 基本介绍 单例案例 类 ...

  4. Java 实现享元(Flyweight)模式

    /*** 字母* @author stone**/ public class Letter {private String name;public Letter(String name) {this. ...

  5. 设计模式学习笔记--Mediator 中介者模式

    我们知道面向对象应用程序是由一组为了提供某种服务而彼此交互的对象组成.当彼此引用的对象数量比较少时,此时对象之间就为直接交互(点对点).而当对象的数量增加时,这种直接交互会导致对象之间复杂的.混乱的引 ...

  6. python 享元模式_python 设计模式之享元(Flyweight)模式

    #写在前面 这个设计模式理解起来很容易.百度百科上说的有点绕口. #享元模式的定义 运用共享技术来有効地支持大量细粒度对象的复用. 它通过共享已经存在的对橡大幅度减少需要创建的对象数量.避免大量相似类 ...

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

    模式定义 运用共享技术有效地支持大量细粒度的对象 类图 应用场景 如果系统有大量类似的对象,可以使用享元模式 优点 如果系统有大量类似的对象,可以节省大量的内存及CPU资源 要点总结 要点总结 如果系 ...

  8. java 地图模式_Java设计模式之从[Dota地图]分析享元(Flyweight)模式

    在Dota游戏的地图中有几百棵树,现在假设这些树木无非是这两种:白杨.枫树,数量一共为400棵,那么,在装载这个地图场景的时候,我们是不是应该给这400课树一一建立对象呢?(如:MapItem tre ...

  9. 设计模式(11)——享元(Flyweight)模式

    什么是享元模式? 享元模式跟CACHE机制类似,它运用共享技术有效地支持大量细粒度的对象.Flyweight通过尽可能地与其他对象共享数据来减少对内存的使用. Flyweight的经典例子就是字符处理 ...

最新文章

  1. visio二次开发___事件篇___事件分类
  2. 分享一个现代的,免费的,简单而有效的编辑器Vis
  3. Microsoft Visual Studio 2010 和 TFS 下载
  4. Scala可变数组和不可变数组之间相互转换
  5. 保护 .NET Core 项目的敏感信息
  6. koa2 中使用 svg-captcha 生成验证码
  7. Android 设备的CPU类型(通常称为”ABIs”)
  8. 印度18岁天才少年,造出“全球最小卫星”,实力不容小觑!
  9. C++静态联编与动态联编
  10. Java String.indexOf() 函数用法小结
  11. 20201124:力扣第216场周赛(上)
  12. 上一页、下一页链接(采用分页方式)
  13. USB VIDPID 表
  14. 印尼Widya Robotics携手华为云,让建筑工地安全看得见
  15. Wordpress主题制作基础教程
  16. 常见系统故障修复(二)——修复GRUB引导故障
  17. 【ChatGPT整活大赏】写论文后自动生成视频
  18. 分布式存储大行其道 浪潮AS13000何以“木秀于林”?
  19. 社会工程常见攻击方式
  20. Dynamic DMA mapping Guide

热门文章

  1. Hadoop Streaming 实战: 多路输出
  2. 基于OpenCV的视频处理 - 人脸检测
  3. 鸿蒙有没有访客账户,华为鸿蒙系统第三“用户”出现?没想到是它
  4. ChaosBlade
  5. 支付宝开通海外退税 阿里腾讯暗战跨境O2O_21世纪网
  6. 小微企业——信贷政策分析
  7. shell 进入hadoop_hadoop的shell命令操作
  8. idea中一键生成copyright
  9. HTTP请求OPTION
  10. Android接入微信登陆