享元模式(Flyweight),运用共享技术有效的支持大量细粒度的对象。
FlyweightFactory,享元工厂,负责创建管理享元对象。
Flyweight,所有具体享元类的超类或接口。
ConcreteFlyweight,需要共享的具体享元类。
UnsharedConcreteFlyweight,不需要共享的具体享元类。
Flyweight
abstract class Flyweight {
public abstract void operation(int extrinsicstate);
}
需要共享的具体Flyweight子类
class ConcreteFlyweight extends Flyweight {
public void operation(int extrinsicstate){
System.out.println("具体Flyweight:"+extrinsicstate);
}
}
不需要共享的Flyweight子类
class UnsharedConcreteFlyweight extends Flyweight {
public void operation(int extrinsicstate){
System.out.println("不共享的具体Flyweight:"+extrinsicstate);
}
}
享元工厂
class FlyweightFactory {
private Hashtable<String,Flyweight> flyweights = new Hashtable<String,Flyweight>();
public FlyweightFactory(){
flyweights.put("X", new ConcreteFlyweight());
flyweights.put("Y", new ConcreteFlyweight());
flyweights.put("Z", new ConcreteFlyweight());
}
public Flyweight getFlyweight(String key) {
return (Flyweight)flyweights.get(key);
}
}
客户端
public class Test {
public static void main(String[] args) {
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
int extrinsicstate = 22;
FlyweightFactory f = new FlyweightFactory();
// 需要共享的类,从工厂得到。
Flyweight fx = f.getFlyweight("X");
fx.operation(--extrinsicstate);
Flyweight fy = f.getFlyweight("Y");
fy.operation(--extrinsicstate);
Flyweight fz = f.getFlyweight("Z");
fz.operation(--extrinsicstate);
// 不需要共享的类,直接实例化。
Flyweight uf = new UnsharedConcreteFlyweight();
uf.operation(--extrinsicstate);
System.out.println();
System.out.println("**********************************************");
}
}
在享元模式中,利用工厂得来实现对象的共享,在使用中,需要通过工厂得到享元对象。在工厂中初始化的时候实例化出对象,也可以什么都不做,在需要的时候进行实例化。
网站共享代码,对于同一分类下的网站,可以使用同一套代码。
抽象的网站类
abstract class WebSite{
public abstract void use();
}
具体网站类
class ConcreteWebSite extends WebSite {
private String name = "";
public ConcreteWebSite(String name) {
this.name = name;
}
public void use() {
System.out.println("网站分类:" + name);
}
}
网站工厂
class WebSiteFactory {
private Hashtable<String,WebSite> flyweights = new Hashtable<String,WebSite>();
//获得网站分类
public WebSite getWebSiteCategory(String key)
{
if (!flyweights.contains(key))
flyweights.put(key, new ConcreteWebSite(key));
return (WebSite)flyweights.get(key);
}
//获得网站分类总数
public int getWebSiteCount()
{
return flyweights.size();
}
}
客户端
public class Test {
public static void main(String[] args) {
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
WebSiteFactory f = new WebSiteFactory();
WebSite fx = f.getWebSiteCategory("产品展示");
fx.use();
WebSite fy = f.getWebSiteCategory("产品展示");
fy.use();
WebSite fz = f.getWebSiteCategory("产品展示");
fz.use();
WebSite fl = f.getWebSiteCategory("博客");
fl.use();
WebSite fm = f.getWebSiteCategory("博客");
fm.use();
WebSite fn = f.getWebSiteCategory("博客");
fn.use();
System.out.println("网站分类总数为:"+f.getWebSiteCount()); //统计实例化个数,结果应该为2
System.out.println();
System.out.println("**********************************************");
}
}
在网站工厂中,如果已经有了相同类型的网站,则会直接返回已有的对象,如果没有该类型的网站,则会创建出来对象,放入哈希表中。
通过工厂实现了相同类别网站共享相同的对象。
在享元对象内部并且不会随环境改变而改变的共享部分,可以称为享元对象的内部状态,而随环境改变而改变的,不可以共享的状态就是外部状态。
将外部状态放在外部进行存储,当调用享元对象进行操作时,将外部状态传递给享元对象。
在网站中,客户的账号就是外部状态,应该放在外部,由专门的对象来处理。
class User{
private String name;
public User(String value){
this.name=value;
}
public String getName(){
return this.name;
}
}
抽象的网站类
abstract class WebSite{
public abstract void use(User user);
}
具体网站类
class ConcreteWebSite extends WebSite {
private String name = "";
public ConcreteWebSite(String name) {
this.name = name;
}
// 调用的时候,将外部状态传递过来
public void use(User user) {
System.out.println("网站分类:" + name+" 用户:"+user.getName());
}
}
网站工厂
class WebSiteFactory {
private Hashtable<String,WebSite> flyweights = new Hashtable<String,WebSite>();
//获得网站分类
public WebSite getWebSiteCategory(String key)
{
if (!flyweights.contains(key))
flyweights.put(key, new ConcreteWebSite(key));
return (WebSite)flyweights.get(key);
}
//获得网站分类总数
public int getWebSiteCount()
{
return flyweights.size();
}
}
客户端
public class Test {
public static void main(String[] args) {
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
WebSiteFactory f = new WebSiteFactory();
WebSite fx = f.getWebSiteCategory("产品展示");
// 调用的时候,将外部状态传递过来
fx.use(new User("小菜"));
WebSite fy = f.getWebSiteCategory("产品展示");
fy.use(new User("大鸟"));
WebSite fz = f.getWebSiteCategory("产品展示");
fz.use(new User("娇娇"));
WebSite fl = f.getWebSiteCategory("博客");
fl.use(new User("老顽童"));
WebSite fm = f.getWebSiteCategory("博客");
fm.use(new User("桃谷六仙"));
WebSite fn = f.getWebSiteCategory("博客");
fn.use(new User("南海鳄神"));
System.out.println("网站分类总数为:"+f.getWebSiteCount());
System.out.println();
System.out.println("**********************************************");
}
}
在调用享元对象的时候,将外部状态传递给享元对象。
何时应用享元模式?
如果一个应用程序使用了大量的对象,而大量的这样对象造成了很大的存储开销时,就应该考虑使用。还有就是对象的大多数状态可以是外部状态,如果删除了外部状态,就可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。
享元模式,共享了对象,可以减少实例,可以节约存储空间。
享元模式的应用,在Java中,字符串常量池就是运用了享元模式。
String titleA = new String("大话设计模式");
String titleB = new String("大话设计模式");
System.out.println(" titleA==titleB: " + (titleA == titleB)); // 输出 false
System.out.println(" titleA.equals(titleB): " + (titleA.equals(titleB))); // 输出 true
String titleC = "大话设计模式";
String titleD = "大话设计模式";
System.out.println(" titleC==titleD: " + (titleC == titleD)); // 输出 true
System.out.println(" titleC.equals(titleD): " + (titleC.equals(titleD))); // 输出 true
对于相同的字符串,只创建了一份,下次再创建已有的字符串,只是将引用指向同一个地址。(new 是显示创建新的对象,所以创建了两个对象。)