[设计模式]享元模式

github地址:https://github.com/1711680493

点我进入github

如需了解更多设计模式,请进入我的设计模式专栏

享元模式

运用共享技术来有效地支持大量细粒度对象的复用.

它通过共享已经存在的对象来大幅度减少需要创建的对象数量,避免大量相似类的开销,从而提高系统资源的利用率

 优点

相同对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力

 缺点

为了使对象可以共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性.

读取享元模式的外部状态会使得运行时间稍微变长.

 享元模式存在两种状态
        内部状态:即不会随着环境的改变而改变可共享部分.
        外部状态:指随环境改变而改变的不可以共享的部分.

        享元模式的实现要领就是区分应用中的这两种状态,并将外部状态外部化

结构

1.抽象享元角色:是所有具体享元类的基类,为具体享元规范需要实现的公共接口,

    非享元的外部状态以参数的形式通过方法传入
2.具体享元角色:实现抽象享元角色中所规定的接口
3.非享元角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中
4.享元工厂角色:负责创建和管理享元角色,当客户对象请求一个享元对象时,
            享元工厂检查系统中是否存在符合要求的享元对象,如果存在则提供给客户
            如果不存在的话,则创建一个新的享元对象

 例子

五子棋等网络游戏可以使用到享元模式,这里举的例子就以共享单车来举例,共享单车是由工厂制造的,并且不同种类的数量是已知的,有限的,共享单车有不同的颜色,这里使用享元模式来获取共享单车.

/**
 * 享元模式
 * @author Shendi <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
 * @version 1.0
 */
public class Flyweight {
	public static void main(String[] args) {
		//创建人
		Person p1 = new Person("张三");
		Person p2 = new Person("李四");
		//使用单车
		p1.use(VehicleFactory.getBike("绿色"));
		p1.use(VehicleFactory.getBike("黄色"));
		p2.use(VehicleFactory.getBike("绿色"));
		p2.use(VehicleFactory.getBike("黄色"));
		p2.use(VehicleFactory.getBike("黄色"));
		p1.use(VehicleFactory.getBike("绿色"));
	}
}

/**
 * 交通工具 对应抽象享元角色
 * @author Shendi <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
 * @version 1.0
 */
interface Vehicle {
	/**
	 * 使用交通工具
	 * @author Shendi <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
	 * @param name 使用者的名称
	 * @param num 使用的次数
	 */
	void use(String name,int num);
}

/**
 * 共享单车 属于交通工具 对应具体享元角色
 * @author Shendi <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
 * @version 1.0
 */
class Bike implements Vehicle {
	private String color;
	/**
	 * 在单车创建的时候就应该有颜色
	 */
	public Bike(String color) {
		this.color = color;
	}
	
	@Override
	public void use(String name,int num) {
		System.out.println("共享单车被 "+ name + "第 " + num + " 次使用了,颜色是:" + color);
	}
}

/**
 * 人 非享元角色.
 * @author Shendi <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
 * @version 1.0
 */
class Person {
	//每个人都有名字
	private String name;
	//这里记录使用单车的次数
	private int num;
	
	/**
	 * 初始化名字
	 * @param name 名称
	 */
	public Person(String name) {
		this.name = name;
	}
	
	/**
	 * 使用交通工具
	 * @author Shendi <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
	 */
	public void use(Vehicle vehicle) {
		vehicle.use(name,num);
		//使用次数+1
		num++;
	}
}

/**
 * 交通工具工厂 享元工厂角色
 * @author Shendi <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
 * @version 1.0
 */
class VehicleFactory {
	//存现有的交通工具
	private static final HashMap<String,Vehicle> vehicles = new HashMap<>();
	
	/**
	 * 获取单车,根据单车颜色
	 * @author Shendi <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
	 * @param name
	 * @return
	 */
	public static Vehicle getBike(String color) {
		//判断池子里有指定id的单车没,有直接返回,没有就创建
		if (vehicles.containsKey(color)) {
			System.out.println(color + "颜色的单车存在,给你返回");
			return vehicles.get(color);
		} else {
			Vehicle v = new Bike(color);
			//添加进池子里
			vehicles.put(color, v);
			System.out.println(color + "颜色的单车不存在,已成功创建");
			return v;
		}
	}
	
}

 

应用场景

享元模式是通过减少内存中对象的数量来节省内存空间
系统中存在大量相同或相似的对象,这些对象耗费大量的内存资源
大部分的对象可以按照内部状态进行分组,且可将不同部分外部化,这样每一个组只需保存一个内部状态
由于享元模式需要额外维护一个保存享元的数据结构,所以应当在有足够多的享元实例时才值得使用享元模式
        例子:线程池,数据库连接池,Java的字符串

 扩展

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

    (单纯享元以上面的例子来说,就是不存在Person这个类)
复合享元模式:这种享元模式中的有些享元对象是由一些单纯享元对象组合而成的,他们就是符合向原对象,虽然复合享元对象本身不能共享,但它们可以分解成单纯享元对象在被共享

总结 

享元模式就是将同一个对象(其中属性不同)存入管理,下次取如果有此对象则直接返回存的,没有则创建
(所以使用享元模式的场景需要大部分对象)

原创文章 55 获赞 64 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41806966/article/details/105650029
今日推荐