String中的设计模式

享元模式

享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。享元模式结构较为复杂,一般结合工厂模式一起使用。

角色

fw(抽象享元类):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)。

Concretefw(具体享元类):它实现了抽象享元类,其实例称为享元对象;在具体享元类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。

UnsharedConcretefw(非共享具体享元类):并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时可以直接通过实例化创建。

fwFactory(享元工厂类):享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中,享元池一般设计为一个存储“键值对”的集合(也可以是其他类型的集合),可以结合工厂模式进行设计;当用户请求一个具体享元对象时,享元工厂提供一个存储在享元池中已创建的实例或者创建一个新的实例(如果不存在的话),返回新创建的实例并将其存储在享元池中。

单纯享元模式:在单纯享元模式中,所有的具体享元类都是可以共享的,不存在非共享具体享元类。

复合享元模式:将一些单纯享元对象使用组合模式加以组合,还可以形成复合享元对象,这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者则可以共享

在享元模式中引入了享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,当用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。

典型的享元工厂类的代码如下:

class FlyweightFactory { //定义一个HashMap用于存储享元对象,实现享元池 private HashMap fw = newHashMap(); public Flyweight getfw(String key){ //如果对象存在,则直接从享元池获取 if(flyweights.containsKey(key)){ return(Flyweight)fw.get(key); } //如果对象不存在,先创建一个新的对象添加到享元池中,然后返回 else { fw fw = newConcreteFlyweight(); fw.put(key,fw); return fw; } }}

享元类的设计是享元模式的要点之一,在享元类中要将内部状态和外部状态分开处理,通常将内部状态作为享元类的成员变量,而外部状态通过注入的方式添加到享元类中。

典型的享元类代码如下所示:

class fw { //内部状态intrinsicState作为成员变量,同一个享元对象其内部状态是一致的 private String intrinsicState; public Flyweight(String intrinsicState) { this.intrinsicState=intrinsicState; } //外部状态extrinsicState在使用时由外部设置,不保存在享元对象中,即使是同一个对象 public void operation(String extrinsicState) { //...... }}复制代码

享元模式一般的类图如下




java 读写 resource 下的文件_工厂类


示例

一般网盘对于相同的文件只保留一份,譬如有一个场景:当我们上传一部别人上传过的电影,会发现很快就上传完成了,实际上不是真的上传,而是引用别人曾经上传过的那部电影,这样一可以提高我们的用户体验,二可以节约存储空间避免资源浪费

注意:这个场景是小编想的,与一般见到的例子不太一样,小编其实不确定是不是享元模式,请大家多多指教

首先定义一个工具类 HashUtil,计算内容的hash值(注:计算hash是从 www.cnblogs.com/oxgen/p/396… 处复制的)

public class HashUtil { public static String computeHashId(String key) { String cacheKey; try { final MessageDigest mDigest = MessageDigest.getInstance("MD5"); mDigest.update(key.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (NoSuchAlgorithmException e) { cacheKey = String.valueOf(key.hashCode()); } return cacheKey; } private static String bytesToHexString(byte[] bytes) { // http://stackoverflow.com/questions/332079 StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.toString(); }}复制代码

资源类 Resource,相当于享元类的内部状态

public class Resource { private String hashId; private int byteSize; private String content; public Resource(String content) { this.content = content; this.hashId = HashUtil.computeHashId(content); // 文件的hash值 this.byteSize = content.length(); } // ....getter、setter、toString...}复制代码

用户的文件类 File,其中的 resource 为内部状态,owner和filename为外部状态

public class File { protected String owner; protected String filename; protected Resource resource; public File(String owner, String filename) { this.owner = owner; this.filename = filename; } public String fileMeta() {// 文件存储到文件系统中需要的key if (this.owner == null || filename == null || resource == null) { return "未知文件"; } return owner + "-" + filename + resource.getHashId(); } public String display() { return fileMeta() +