一、享元模式(Flyweight):
意图:运用共享技术有效地支持大量细粒度的对象。享元模式可以使你共享地访问那些大量出现的细粒度对象,享元对象必须是不可变的,可以将那些不变的部分提取出来。
享元模式的重点在于分离变与不变。本质是分离与共享。把一个对象的状态分成内部状态和外部状态,内部状态是不变的,外部状态是可变的。然后通过共享不变的部分,达到减少对象数量并节约内存的目的。
内部状态:通常指的是包含在享元对象内部的、对象本身的状态,不会随享元环境而变化,因此可共享;外部状态:是享元对象之外的状态,取决于使用享元的场景,会根据使用场景而变化,因此不可共享。如果享元对象需要这些外部状态的话,可以从外部传到外部状态中。外部状态和内部状态是相互独立的,外部状态的变换不会因起内部状态的变化。为了确定你的享元对象能够被共享,需要提供并强制客户对象使用享元工厂来查找享元对象。
具体享元角色:抽象享元角色的具体实现类,并实现了抽象享元角色规定的方法。
(1)如果一个应用程序使用了大量的细粒度对象,可以使用享元模式来减少对象数量。
(2)如果使用大量的对象,造成很大的存储开销,可以使用享元模式来减少对象数量,并节约内存。
(3)如果对象的大多数状态都可以转变为外部状态,可以使用享元对象来实现外部状态与内部状态的分离。
意图:运用共享技术有效地支持大量细粒度的对象。享元模式可以使你共享地访问那些大量出现的细粒度对象,享元对象必须是不可变的,可以将那些不变的部分提取出来。
享元模式的重点在于分离变与不变。本质是分离与共享。把一个对象的状态分成内部状态和外部状态,内部状态是不变的,外部状态是可变的。然后通过共享不变的部分,达到减少对象数量并节约内存的目的。
内部状态:通常指的是包含在享元对象内部的、对象本身的状态,不会随享元环境而变化,因此可共享;外部状态:是享元对象之外的状态,取决于使用享元的场景,会根据使用场景而变化,因此不可共享。如果享元对象需要这些外部状态的话,可以从外部传到外部状态中。外部状态和内部状态是相互独立的,外部状态的变换不会因起内部状态的变化。为了确定你的享元对象能够被共享,需要提供并强制客户对象使用享元工厂来查找享元对象。
二、享元模式结构图:
具体享元角色:抽象享元角色的具体实现类,并实现了抽象享元角色规定的方法。
享元工厂角色:负责创建和管理享元角色,一般需要一个HashMap对象。
三、示例程序:
抽象享元类:
public abstract class WebSite {
protected String type;
public abstract void use(User user);
public WebSite(String type) {
this.type = type;
}
}
具体享元角色:
public class ConcurrentWebSite extends WebSite {
public ConcurrentWebSite(String type) {
super(type);
}
@Override
public void use(User user) {
System.out.println("The web site's type is: " + type);
System.out.println("User: " + user.getUserName());
System.out.println("Passwd: " + user.getPassWd() + "\n");
}
}
享元工厂:
import java.util.HashMap;
import java.util.Map;
public class WebSiteFactory {
private static Map<String, WebSite> webSites = new HashMap<String, WebSite>();
private WebSiteFactory() {
}
public static WebSite createWebSite(String type) {
WebSite webSite = webSites.get(type);
if (webSite == null) {
webSite = new ConcurrentWebSite(type);
webSites.put(type, webSite);
}
return webSite;
}
public static int webSitesCount() {
return webSites.size();
}
}
Client:
public class Client {
public static void main(String[] args) {
WebSite wb1 = WebSiteFactory.createWebSite("BusinessWebSite");
User user1 = new User("root", "root");
wb1.use(user1);
WebSite wb2 = WebSiteFactory.createWebSite("BusinessWebSite");
User user2 = new User("admin", "admin");
wb2.use(user2);
WebSite wb3 = WebSiteFactory.createWebSite("BusinessWebSite");
User user3 = new User("slave", "slave");
wb3.use(user3);
System.out.println("WebSites Instances Count: "
+ WebSiteFactory.webSitesCount());
}
}
运行结果:
The web site's type is: BusinessWebSite
User: root
Passwd: root
The web site's type is: BusinessWebSite
User: admin
Passwd: admin
The web site's type is: BusinessWebSite
User: slave
Passwd: slave
WebSites Instances Count: 1
上例中共享的实例就是WebSite,type为内部参数,User作为外部参数传入。本例中的type是PersonalWebSite,即为享元,不可以改变,而user不是享元,根据环境变化而变化。在享元工厂中一般都需要一个HashMap来维护享元对象,如果存在就不需要在创建,不存在就添加。
享元模式的优缺点:(1)优点:减少对象数量,节省内存空间;(2)缺点:维护共享对象,需要额外的开销(用一个线程来维护垃圾回收)。
何时使用享元对象:(1)如果一个应用程序使用了大量的细粒度对象,可以使用享元模式来减少对象数量。
(2)如果使用大量的对象,造成很大的存储开销,可以使用享元模式来减少对象数量,并节约内存。
(3)如果对象的大多数状态都可以转变为外部状态,可以使用享元对象来实现外部状态与内部状态的分离。