享元模式 :
运用共享技术有效的支持大量细粒度的对象。
动机:在软件系统采用纯粹对象方案(一切皆对象)的问题在于大量细粒度的对象会很快充斥再系统中,从而带来很高的运行时代价---------主要指内存需求方面的代价。
问题的引入----创建网站简单代码
网站类
public class WebSite {
private String name = "";
public WebSite(String name) {
this.name = name;
}
public void Use() {
System.out.println("网站分类:" + name);
}
}
客户端代码
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
WebSite fx=new WebSite("产品展示");fx.Use();
WebSite fy=new WebSite("产品展示");fy.Use();
WebSite fz=new WebSite("产品展示");fz.Use();
WebSite fl=new WebSite("博客");fl.Use();
WebSite fm=new WebSite("博客");fm.Use();
WebSite fn=new WebSite("博客");fn.Use();
}
}
简单代码的问题
其实它们本质上都是一样的代码,如果网站增多,实例也随之增多,对服务器造成资源浪费。
解决方法:1.网站公用一套代码。–但不同的网站数据不同,否定。
2.利用用户ID不同来区分不同的用户,各个小网站的具体数据和模板可以不同,但核心代码和数据库却是共享的。
内部状态和外部状态
享元对象能做到共享的关键是区分内部状态的外部状态。
内部状态是存储在享元对象内部并且不会随环境改变而改变。因此内部状态可以共享。
外部状态是随环境改变而改变的、不可共享的状态。享元对象的外部状态必须由客户端保存,并在享元对象被创建后,再需要使用的时候再传入到享元对象内部。
外部状态和内部状态是相互独立的。
享元模式结构图
享元模式具体代码
Flyweight工厂
public abstract class Flyweight {
//是所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态
public String intrinsic;//内部状态
protected final String extrinsic;//外部状态
//要求享元角色必须接受外部状态
public Flyweight(String extrinsic) {
this.extrinsic=extrinsic;
}
public abstract void operate(int ectrinsic) ;//定义业务操作
public String getIntrinsic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic=intrinsic;
}
}
共享的和不共享的
public class ConcreteFlyweight extends Flyweight{
public ConcreteFlyweight(String extrinsic) {
super(extrinsic);
// TODO 自动生成的构造函数存根
}
public void operate(int extrinsic) {
System.out.println("具体Flyweight:"+extrinsic);
}
}
public class UnsharedConcentrateFlyweight extends Flyweight{
public UnsharedConcentrateFlyweight(String extrinsic) {
super(extrinsic);
// TODO 自动生成的构造函数存根
}
public void operate(int extrinsic) {
System.out.println("不共享的具体Flyweight:"+extrinsic);
}
}
享元工厂
import java.util.HashMap;
public class FlyweightFactory {
//定义一个池容器
private static HashMap<String,Flyweight> pool=new HashMap<String ,Flyweight>();
public static Flyweight getFlyweight(String extrinsic) {
Flyweight flyweight=null;
if(pool.containsKey(extrinsic)) {//池中有该对象
flyweight=pool.get(extrinsic);
System.out.println("已有"+extrinsic+"直接从池中取---->");
}else {//根据外部状态创建享元对象
flyweight=new ConcreteFlyweight(extrinsic);//放入池中
System.out.println("创建"+extrinsic+"并从池中取出--->");
}
return flyweight;
}
}
客户端代码
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
int extrinsic=22;
FlyweightFactory f=new FlyweightFactory();
Flyweight flyweightX=f.getFlyweight("X");
flyweightX.operate(--extrinsic);
Flyweight flyweightY=f.getFlyweight("Y");
flyweightX.operate(--extrinsic);
Flyweight flyweightZ=f.getFlyweight("Z");
flyweightX.operate(--extrinsic);
Flyweight flyweightReX=f.getFlyweight("X");
flyweightX.operate(--extrinsic);
Flyweight unsharedFlyweight=new UnsharedConcentrateFlyweight("X");
unsharedFlyweight.operate(--extrinsic);
}
}
结果
网站共享代码(无外部状态的享元模式)
public abstract class WebSite1 {
public abstract void Use();
}
public class ConcreteWebSite extends WebSite1{
private String name="";
public ConcreteWebSite(String name) {
this.name = name;
}
@Override
public void Use() {
// TODO 自动生成的方法存根
System.out.println("网站分类:"+name);
}
}
import java.util.HashMap;
public class WebSiteFactory {
//定义一个池容器
private static HashMap<String,WebSite1> flyweights=new HashMap<String ,WebSite1>();
//获得网站分类
public WebSite1 GetWebSiteCategory(String key) {
if(!flyweights.containsKey(key)) {
WebSite1 flyweight=new ConcreteWebSite(key);
flyweights.put(key, flyweight);
}
return flyweights.get(key);
}
public int GetWebSiteCount() {
return flyweights.size();
}
}
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
WebSiteFactory f=new WebSiteFactory();
WebSite1 fx=f.GetWebSiteCategory("产品展示");fx.Use();
WebSite1 fy=f.GetWebSiteCategory("产品展示");fy.Use();
WebSite1 fz=f.GetWebSiteCategory("产品展示");fz.Use();
WebSite1 fl=f.GetWebSiteCategory("博客");fl.Use();
WebSite1 fm=f.GetWebSiteCategory("博客");fm.Use();
WebSite1 fn=f.GetWebSiteCategory("博客");fn.Use();
System.out.println("网站分类总数为"+f.GetWebSiteCount());
}
}
实际上这样写没有体现对象间的不同。
在网站的例子中,客户账号就是外部状态,应该由专门的对象来处理。
带外部状态的网站共享代码
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public abstract class WebSite2 {
public abstract void Use(User user);
}
//具体网站类
public class ConcreteWebSite1 extends WebSite2{
private String name="";
public ConcreteWebSite1(String name) {
this.name = name;
}
@Override
public void Use(User user) {
// TODO 自动生成的方法存根
System.out.println("网站分类:"+name+"用户:"+user.getName());
}
}
import java.util.HashMap;
public class WebSiteFactory1 {
//定义一个池容器
private static HashMap<String,WebSite2> flyweights=new HashMap<String ,WebSite2>();
//获得网站分类
public WebSite2 GetWebSiteCategory(String key) {
if(!flyweights.containsKey(key)) {
WebSite2 flyweight=new ConcreteWebSite1(key);
flyweights.put(key, flyweight);
}
return flyweights.get(key);
}
public int GetWebSiteCount() {
return flyweights.size();
}
}
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
WebSiteFactory1 f=new WebSiteFactory1();
WebSite2 fx=f.GetWebSiteCategory("产品展示");fx.Use(new User("小菜"));
WebSite2 fy=f.GetWebSiteCategory("产品展示");fy.Use(new User("大鸟"));
WebSite2 fz=f.GetWebSiteCategory("博客");fz.Use(new User("娇娇"));
System.out.println("网站分类总数为"+f.GetWebSiteCount());
}
}