享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度的对象。
比如博客或者淘宝店铺,每个博客或者每间店铺之间都有一定的共性和差异,可以为所有的博客都提供一个公共的框架,只是内容可以根据具体博客进行改变,这样可以进行复用节省大量的资源。
基本实现
Flyweight类,可以接收外界状态进而表现出不同的形式
public abstract class Flyweight {
abstract void operation(int extrinsicState);
}
Flyweight可分为共享实现和非共享实现。共享实现可以用来定义那些对象共有的细节。非共享实现可以用来定义一些额外的细节。
共享实现:
public class SharedFlyweight extends Flyweight {
@Override
void operation(int extrinsicState) {
System.out.println("共享的Flyweight:" + extrinsicState);
}
}
非共享实现:
public class UnsharedFlyweight extends Flyweight {
@Override
void operation(int extrinsicState) {
System.out.println("不共享的flyweight:" + extrinsicState);
}
}
创建一个工厂类来管理Flyweight,内部使用容器保存Flyweight。内部Flyweight对象的实例化可以在工厂类创建的时候就进行实例化,也可以根据具体需要临时实例化:
public class FlyweightFactory {
private HashMap<String, Flyweight> flyweights = new HashMap<>();
public FlyweightFactory() {
flyweights.put("X", new SharedFlyweight());
flyweights.put("Y", new SharedFlyweight());
flyweights.put("Z", new SharedFlyweight());
}
public Flyweight getFlyweight(String key) {
return flyweights.get(key);
}
}
测试类:
public class Main {
public static void main(String[] args) {
int extrinsicState = 20;
final FlyweightFactory flyweightFactory = new FlyweightFactory();
final Flyweight flyweightX = flyweightFactory.getFlyweight("X");
flyweightX.operation(--extrinsicState);
final Flyweight flyweightY = flyweightFactory.getFlyweight("Y");
flyweightY.operation(--extrinsicState);
final Flyweight flyweightZ = flyweightFactory.getFlyweight("Z");
flyweightZ.operation(--extrinsicState);
final UnsharedFlyweight unsharedFlyweight = new UnsharedFlyweight();
unsharedFlyweight.operation(--extrinsicState);
}
}
输出:
共享的Flyweight:19
共享的Flyweight:18
共享的Flyweight:17
不共享的flyweight:16
具体实例
网站类:
public abstract class Website {
abstract void show(String title);
}
具体网站类:
public class ConcreteWebsite extends Website {
private String category;
public ConcreteWebsite(String category) {
this.category = category;
}
@Override
void show(String title) {
System.out.println("网站分类:" + category + ",网站名:" + title);
}
}
工厂类:
public class WebsiteFactory {
private HashMap<String, Website> websites = new HashMap<>();
public Website getWebsite(String category) {
if (!websites.containsKey(category)) {
websites.put(category, new ConcreteWebsite(category));
}
return websites.get(category);
}
public int getWebsitesCount() {
return websites.size();
}
}
测试类:
public class Main {
public static void main(String[] args) {
final WebsiteFactory websiteFactory = new WebsiteFactory();
final Website websiteA = websiteFactory.getWebsite("店铺");
websiteA.show("零食店");
final Website websiteB = websiteFactory.getWebsite("店铺");
websiteB.show("服装店");
final Website websiteC = websiteFactory.getWebsite("博客");
websiteC.show("tim's blog");
final Website websiteD = websiteFactory.getWebsite("博客");
websiteD.show("shin's blog");
System.out.println("total instance of websites: " + websiteFactory.getWebsitesCount());
}
}
输出:
网站分类:店铺,网站名:零食店
网站分类:店铺,网站名:服装店
网站分类:博客,网站名:tim's blog
网站分类:博客,网站名:shin's blog
total instance of websites: 2
所以享元模式可以定义几种基本的享元类,根据外界条件进行不同的实现,保持尽量少的对象实例。
比如Java虚拟机的字符串常量也是复用已存在的。或者五子棋游戏中棋子的坐标是外部状态,诸多棋子只要使用两个黑白实例实现就可以了。