Java设计模式(二十二)---享元模式

x33g5p2x  于2021-03-13 发布在 Java  
字(3.5k)|赞(0)|评价(0)|浏览(172)

定义:使用共享对象可有效的支持大量的细粒度的对象。
享元模式的定义为我们提出了两个要求:细粒度的对象和共享对象。
我们知道分配太多的对象到应用程序中将有损程序的性能,同时还容易造成内存溢出。享元模式就可以有效的避免。
细粒度对象由于是对象数量多且性质相近,我们将这些对象分为两个部分:内部状态和外部状态。
内部状态:
---|内部状态是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改变。如id,address等。
外部状态:
---|外部状态是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态。如考试科目+考试地点等。

一般模式

Flyweight抽象享元角色
---|产品的抽象类,定义出对象的外部状态和内部状态的接口或实现
ConcreteFlyweight具体享元角色
---|实现抽象角色定义的义务。该角色要注意内部状态处理与环境无关,不能出现一个操作改变内部状态,同时修改外部状态。
unShareConcreteFlyweight不可共享的享元角色
---|不存在外部状态或者安全要求不能够使用共享技术的对象,该对象一般不会出现在享元工厂中。
FlyweightFactory享元工厂

---|职责非常简单,就是构造一个池容器,同时提供从池中获得对象的方法。

public class FlyweightTest {

}
/**
 * 抽象的享元角色。
 * 定义出对象的外部状态和内部状态的接口和实现。
 * @author admin
 */
abstract class Flyweight{
	//内部状态
	private String intrinsic;
	//外部状态
	protected String extrinsic;
	
	//构造方法提供外部字符串
	public Flyweight(String extrinsic) {
		this.extrinsic = extrinsic;
	}
	
	//定义业务操作
	public abstract void operate();
	//内部状态的getter和
	public String getIntrinsic() {
		return intrinsic;
	}
	public void setIntrinsic(String intrinsic) {
		this.intrinsic = intrinsic;
	}
}
/**
 * 具体的享元角色
 * @author admin
 */
class ConcreteFlyweight1 extends Flyweight{

	public ConcreteFlyweight1(String extrinsic) {
		super(extrinsic);
	}
	@Override
	public void operate() {
		System.out.println("享元角色1...操作");
	}
}
/**
 * 具体的享元角色
 * @author admin
 */
class ConcreteFlyweight2 extends Flyweight{

	public ConcreteFlyweight2(String extrinsic) {
		super(extrinsic);
	}

	@Override
	public void operate() {
		System.out.println("享元角色2...操作");
	}
}
/**
 * 享元工厂角色
 * @author admin
 */
class FlyweightFactory{
	//定义一个容器
	private static HashMap<String, Flyweight> pool = new HashMap<String, Flyweight>();
	//享元工厂
	public static Flyweight getFlyweight(String extrinsic){
		//需要返回的对象
		Flyweight flyweight=null;
		if(!pool.containsKey(extrinsic)){
			//根据外部状态创建享元对象
			flyweight = new ConcreteFlyweight1(extrinsic);
			pool.put(extrinsic, flyweight);
		}else{
			flyweight = pool.get(extrinsic);
		}
		return flyweight;
	}
}

一个例子

一个学生报考系统,该系统限时3天注册并报名。每天的访问量达上百万,人数极多。系统开发完,出现了OOM内存溢出
的状况。产生该问题的原因有两种:
1、内存溢出(无意识的代码缺陷,导致JVM不能获得连续的内存空间)
2、对象太多,把内存耗尽了。
享元模式来解决,来限制对象的创建。

public class FlyweightT {
	public static void main(String[] args) {
		//创建对象
		for(int i=0;i<4;i++){
			String subject = "科目"+i;
			for(int j=0;j<30;j++){
				String location = "地点"+j;
			SignInfo signInfo = SignInfoFactory.getSignInfo(subject+location);
			}
		}
		SignInfo s = SignInfoFactory.getSignInfo("科目3地点4");
	}
}
/**
 * 抽象的学生享元角色
 * 提供学生的一些基本信息。
 * @author admin
 */
abstract class SignInfo{
	//学生id
	private String id;
	//学生考试地点
	private String location;
	//考试科目
	private String subject;
	//考试
	private String postAddress;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getLocation() {
		return location;
	}
	public void setLocation(String location) {
		this.location = location;
	}
	public String getSubject() {
		return subject;
	}
	public void setSubject(String subject) {
		this.subject = subject;
	}
	public String getPostAddress() {
		return postAddress;
	}
	public void setPostAddress(String postAddress) {
		this.postAddress = postAddress;
	}
}
/**
 * 具体的享元角色,
 * 设置外部状态。
 * @author admin
 *
 */
class SignInfo4Pool extends SignInfo{
	private String key;
	
	public SignInfo4Pool(String key) {
		this.key = key;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}
}
/**
 * 享元工厂类。
 * 创建对象享元对象
 * @author admin
 *
 */
class SignInfoFactory{
	private static HashMap<String, SignInfo> pool = new HashMap<String, SignInfo>();
	public static SignInfo getSignInfo(String key){
		
		SignInfo signInfo =null;
		if(pool.containsKey(key)){
			System.out.println("从对象池中获取...");
			signInfo = pool.get(key);
		}else{
			System.out.println("创建新对象...");
			signInfo = new SignInfo4Pool(key);
			pool.put(key, signInfo);
		}
		return signInfo;
	}
}

享元模式的优缺点:
大大减少了应用程序创建的对象,降低程序内存的占用,增强程序的性能。
使用享元模式时,外部状态尽量使用java提供的基本数据类型,提高程序的性能。
使用场景:

系统中存在大量的相似对象,细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是对象没有特定身份,需要缓冲池的场景

相关文章