什么是享元模式?

一、前言

    享元模式是构造型模式之一,它通过共享数据使得相同对象在内存中仅创建一个实例,以降低系统创建对象实例的性能消耗。
    以博客里写文章为例来说吧,把文章和文章中的文字看作对象,我们每在博客里写一个字就相当于是创建一个文字对象,假如我们写的文章有一万个字,那我们岂不是要创建一万次文字对象,如此频繁的创建对象势必会严重拖累系统的性能。
    享元模式通过数据共享使得重复使用的相同对象在内存中仅创建一次:这就好比汉字中的 “的” 字虽然在文章中反复出现,但它仅在第一次被使用的时候创建 “的” (共享对象)并保存起来,之后再用到 “的” 字的话直接获取之前创建好的 “的” 对象即可,不需要再次创建了。

下面是两张使用享元模式前后的对比图,看完这两张图相信大家就能理解享元模式的作用了。

  • 使用享元模式前:
    在这里插入图片描述
  • 使用享元模式后:
    在这里插入图片描述

二、享元模式在Java中的典型应用

    在Java语言中,String类型就使用了享元模式。String对象是final类型,对象一旦创建就不可改变,同时JAVA会确保一个字符串常量(例如:“Flyweight”)在常量池中只能存在一份拷贝,例如下面这段简单代码:

  String str1="Flyweight";
  String str2="Flyweight";
 
  if(str1==str2){
   System.out.println("str1与str2指向同一对象");
  }
  else
  {
   System.out.println("str1与str2指向不同对象");
  }

打印结果:

str1与str2指向同一对象

    在以上代码中if语句比较的是对象str1和str2中存储的内存地址是否相同,从最终的打印结果可以看出:两次创建的字符串常量"Flyweight"内存地址相同,即两个字符串其实是同一个对象。

三、享元模式的结构

享元模式分为单纯享元模式和复合享元模式两种,这里只介绍单纯享元模式。

单纯享元模式

在这里插入图片描述
1)单纯享元模式涉及的角色及其职责如下:

  • 抽象享元角色:所有具体享元类的父类或实现的接口,以规定所有具体享元角色需要实现的方法;
  • 具体享元(ConcreteFlyweight)角色:又叫单纯享元角色,是抽象享元角色的具体实现类,如果有内蕴状态的话,它负责为内蕴状态提供存储空间。具体享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享;
  • 享元工厂(FlyweightFactory)角色:负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当客户端调用某个享元对象的时候,享元工厂角色会检查系统中是否已经存在符合要求的享元对象,如果已经存在则直接提供,若不存在则新创建一个;

2)单纯享元模式结构示意源代码如下:

在单纯的享元模式中,Flyweight接口用以规定出所有具体享元角色需要实现的方法。

public interface Flyweight {
	/**
	 * 用以规定所有具体享元角色需要实现的方法.
	 */
	void operation(String extrinsicState);
}

    具体享元ConcreteFlyweight一方面要保存需共享的内蕴状态,另一方面将外蕴状态作为参数传入operation()方法中,可改变方法的行为,但并不改变对象的内蕴状态。

public class ConcreteFlyweight implements Flyweight {
 
	private String intrinsicState = null;
 
	/**
	 * 构造函数中内蕴状态作为参数传入.
	 */
	public ConcreteFlyweight(String intrinsicState) {
		this.intrinsicState = intrinsicState;
	}
 
	/**
	 * 外蕴状态作为参数传入方法中,可改变方法的行为,但并不改变对象的内蕴状态.
	 */
	@Override
	public void operation(String extrinsicState) {
		System.out.println();
		System.out.println("内蕴状态:" + intrinsicState);
		System.out.println("外蕴状态:" + extrinsicState);
		System.out.println("-------------------------");
	}
 
	public String toString() {
		return this.intrinsicState;
	}
}

    享元工厂FlyweightFactory负责维护一个享元对象存储池(Flyweight Pool)来存放内部状态的对象。为了调用方便,该工厂类一般使用单例模式来实现。

import java.util.HashMap;
import java.util.Map;
 
public class FlyweightFactory {
 
	// 用来登记和存储已经创建过的享元对象
	private Map<String, Flyweight> flyweightMap = new HashMap<String, Flyweight>();
 
	// 采用单例模式
	private static FlyweightFactory flyweightFactory = new FlyweightFactory();
 
	// 私有化享元工厂的构造方法
	private FlyweightFactory() {
	}
 
	// 获取单例享元工厂的实例
	public static FlyweightFactory getFlyweightFactory() {
		return flyweightFactory;
	}
 
	public Flyweight getFlyweight(String intrinsicState) {
		Flyweight flyweight = flyweightMap.get(intrinsicState);
		if (null == flyweight) {
			flyweight = new ConcreteFlyweight(intrinsicState);
			flyweightMap.put(intrinsicState, flyweight);
		}
		return flyweight;
	}
 
	public Map<String, Flyweight> getFlyweightMap() {
		return flyweightMap;
	}
}

在Client类中创建的main()方法中进行测试。

import java.util.Map.Entry;
 
public class Client {
 
	public static void main(String[] args) {
		FlyweightFactory flyweightFactory = FlyweightFactory.getFlyweightFactory();
		flyweightFactory.getFlyweight("爱").operation("位置1");
		flyweightFactory.getFlyweight("我").operation("位置2");
		flyweightFactory.getFlyweight("的").operation("位置3");
		flyweightFactory.getFlyweight("人").operation("位置4");
		flyweightFactory.getFlyweight("和").operation("位置5");
		flyweightFactory.getFlyweight("我").operation("位置6");
		flyweightFactory.getFlyweight("爱").operation("位置7");
		flyweightFactory.getFlyweight("的").operation("位置8");
		flyweightFactory.getFlyweight("人").operation("位置9");
		
		System.out.println("已存储的享元对象个数:"+flyweightFactory.getFlyweightMap().size()+"个");
		for (Entry<String, Flyweight> entry : flyweightFactory.getFlyweightMap().entrySet()) {
			System.out.println(entry.getValue());
		}
	}
}

运行程序打印结果如下:

内蕴状态:爱
外蕴状态:位置1
-------------------------

内蕴状态:我
外蕴状态:位置2
-------------------------

内蕴状态:的
外蕴状态:位置3
-------------------------

内蕴状态:人
外蕴状态:位置4
-------------------------

内蕴状态:和
外蕴状态:位置5
-------------------------

内蕴状态:我
外蕴状态:位置6
-------------------------

内蕴状态:爱
外蕴状态:位置7
-------------------------

内蕴状态:的
外蕴状态:位置8
-------------------------

内蕴状态:人
外蕴状态:位置9
-------------------------
已存储的享元对象个数:5个
爱
我
的
人
和

    从以上程序的运行结果不难看出,虽然我们新建了9个Flyweight对象,但在内存池中实际上只有5个,这就是共享的含义。

转载:《JAVA设计模式–享元模式》

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值