设计模式之享元模式

享元模式的目的是复用。复用那些细粒度的小对象,从而减少系统中对象的数量,提高系统性能。

模式的关键:

1. 分清内蕴状态(可共享,对象一旦创建就不能改变)和外蕴状态(不可共享,又外部环境负责维护)

2. FlyweightFactory工厂的存在把获取享元对象的过程封装起来。该工厂一般设计为单例模式。

分为单纯享元模式和复合享元模式。


一、单纯享元模式

1.1 不带外蕴状态的享元模式

import java.util.HashMap;
import java.util.Map;

// 不带外蕴状态的单纯享元模式
public class Test5 {

	public static void main(String[] args) {
		FlyweightFactory factory = FlyweightFactory.getInstance();
		
		Flyweight cf1 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_A);
		cf1.show();
		
		Flyweight cf2 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_B);
		cf2.show();
		
		Flyweight cf3 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_A);
		cf1.show();
	}

}

// 抽象享元
abstract class Flyweight {
	public abstract void show ();
}

// 具体享元类
class ConcreteFlyweight extends Flyweight {
	private char value;  // 内蕴状态,对象创建后,内蕴状态就不再改变。因此,具体享员类一般设计为不变类。
	
	public ConcreteFlyweight(char internalState) {
		this.value = internalState;
	}
	
	@Override
	public void show() {
		System.out.println("字母:" + this.value);
	}
	
}

class FlyweightFactory {
	
	// singleton
	private static final FlyweightFactory instance = new FlyweightFactory();
	
	private Map<String, Flyweight> cache = new HashMap<String, Flyweight>();
	public static final String KEY_CHAR_A = "A";
	public static final String KEY_CHAR_B = "B";
	
	private FlyweightFactory () {}
	
	public static FlyweightFactory getInstance() {
		return instance;
	}
	
	public Flyweight getFlyweight(String key) {
		if (cache.get(key) != null) {
			return cache.get(key);
		}
		
		if (key.equals(KEY_CHAR_A)) {
			cache.put(KEY_CHAR_A, new ConcreteFlyweight('A'));
			return cache.get(key);
		} else if (key.equals(KEY_CHAR_B)) {
			cache.put(KEY_CHAR_B, new ConcreteFlyweight('B'));
			return cache.get(key);
		} 
		
		return null;
	}
}

// 运行结果: (请求了3次,但是只生成了2个对象)

字母:A
字母:B
字母:A


1.2. 带外蕴状态的享元模式

import java.util.HashMap;
import java.util.Map;

// 带外蕴状态的单纯享元模式
public class Test5 {

	public static void main(String[] args) {
		FlyweightFactory factory = FlyweightFactory.getInstance();
		
		Flyweight cf1 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_A);
		cf1.show(" 字体:宋体");  // 外部状态由客户端维护
		
		Flyweight cf2 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_B);
		cf2.show(" 大小:12px");
		
		Flyweight cf3 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_A);
		cf3.show(" 字体:隶书");
	}

}

// 抽象享元
abstract class Flyweight {
	public abstract void show (String externState);  // 业务方法
}

// 具体享元类
class ConcreteFlyweight extends Flyweight {
	private char value;  // 内蕴状态,对象创建后,内蕴状态就不再改变。因此,具体享员类一般设计为不变类。
	
	public ConcreteFlyweight(char internalState) {
		this.value = internalState;
	}
	
	// 外部状态通过参数传给享元对象,从而改变享元对象的行为,但是对享元对象的内部状态没有任何影响
	@Override
	public void show(String externState) {
		System.out.println("字母:" + this.value + "; 外部状态【" + externState + "】");
	}
	
}

class FlyweightFactory {
	
	// singleton
	private static final FlyweightFactory instance = new FlyweightFactory();
	
	private Map<String, Flyweight> cache = new HashMap<String, Flyweight>();
	public static final String KEY_CHAR_A = "A";
	public static final String KEY_CHAR_B = "B";
	
	private FlyweightFactory () {}
	
	public static FlyweightFactory getInstance() {
		return instance;
	}
	
	public Flyweight getFlyweight(String key) {
		if (cache.get(key) != null) {
			return cache.get(key);
		}
		
		if (key.equals(KEY_CHAR_A)) {
			cache.put(key, new ConcreteFlyweight('A'));
			return cache.get(key);
		} else if (key.equals(KEY_CHAR_B)) {
			cache.put(key, new ConcreteFlyweight('B'));
			return cache.get(key);
		} 
		
		return null;
	}
}
运行结果:(请求3次,只生成两个享元对象,但是因为外蕴状态的加入,2个享元对象表现出3种不同的行为) 字母:A; 外部状态【 字体:宋体】
字母:B; 外部状态【 大小:12px】

字母:A; 外部状态【 字体:隶书】


1.3 复合享元模式

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

// 复合享元模式
public class Test5 {

	public static void main(String[] args) {
		FlyweightFactory factory = FlyweightFactory.getInstance();
		
		// 获取单纯享元
		Flyweight cf1 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_A);
		cf1.show(" 字体:宋体");  // 外部状态由客户端维护
		
		Flyweight cf2 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_B);
		cf2.show(" 大小:12px");
		
		Flyweight cf3 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_A);
		cf3.show(" 字体:隶书");
		
		
		// 获取复合享元
		
		Flyweight composit = factory.getFlyweight(Arrays.asList(new String[]{"A","B","B","B","A"}));
		composit.show("粗体、黑色");
	}

}

// 抽象享元
abstract class Flyweight {
	public abstract void show (String externState);  // 业务方法
}

// 具体享元类
class ConcreteFlyweight extends Flyweight {
	private char value;  // 内蕴状态,对象创建后,内蕴状态就不再改变。因此,具体享员类一般设计为不变类。
	
	public ConcreteFlyweight(char internalState) {
		this.value = internalState;
	}
	
	// 外部状态通过参数传给享元对象,从而改变享元对象的行为,但是对享元对象的内部状态没有任何影响
	@Override
	public void show(String externState) {
		System.out.println("字母:" + this.value + "; 外部状态【" + externState + "】");
	}
	
}

//复合享元类。
//之所以引入复合享元,是为了把那些外蕴状态相同的单纯享元集中起来进行管理。
class CompositeFlyweight extends Flyweight {
	
	// 持有单纯享元的集合。这些单纯享元的外蕴状态和当前复合享元的外蕴状态相同。
	private Map<String, Flyweight> map = new HashMap<String, Flyweight>();
	
	public CompositeFlyweight(){}
	
	public void add(String key, Flyweight flyweight) {
		map.put(key, flyweight);
	}
	
	public void show(String externState) {
		Set<String> set = map.keySet();
		for (String key : set) {
			map.get(key).show(externState); // 每个具体的享元的外蕴状态和当前复合享元的外蕴状态相同
		}
	}
}

// 分别提供获取单纯享元和复合享元的方法
class FlyweightFactory {
	
	// singleton
	private static final FlyweightFactory instance = new FlyweightFactory();
	
	private Map<String, Flyweight> cache = new HashMap<String, Flyweight>();
	public static final String KEY_CHAR_A = "A";
	public static final String KEY_CHAR_B = "B";
	
	private FlyweightFactory () {}
	
	public static FlyweightFactory getInstance() {
		return instance;
	}
	
	// 获取单纯享元对象
	public Flyweight getFlyweight(String key) {
		if (cache.get(key) != null) {
			return cache.get(key);
		}
		
		if (key.equals(KEY_CHAR_A)) {
			cache.put(key, new ConcreteFlyweight('A'));
			return cache.get(key);
		} else if (key.equals(KEY_CHAR_B)) {
			cache.put(key, new ConcreteFlyweight('B'));
			return cache.get(key);
		} 
		
		return null;
	}
	
	// 获取复合享元对象
	public Flyweight getFlyweight(List<String> keys) {
		CompositeFlyweight composit = new CompositeFlyweight();
		for (String key : keys) {
			composit.add(key, this.getFlyweight(key)); // 复合享元中的单纯享元还是通过获取单纯享元的方法中得到
		}
		
		return composit;
	}
}


输出结果:

// 单纯享元

字母:A; 外部状态【 字体:宋体】
字母:B; 外部状态【 大小:12px】
字母:A; 外部状态【 字体:隶书】

// 复合享元

字母:A; 外部状态【粗体、黑色】
字母:B; 外部状态【粗体、黑色】



你可能感兴趣的:(设计模式)