享元模式(Flyweigh)
动机:避免大量细粒度对象问题的同时,让外部客户程序扔能够透明地使用面向对象的方式操作。
实例:不同网站具体数据和模板不同,核心代码和数据库共享
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) {
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();
}
}
如果要做三个产品展示,三个博客的网站就需要六个网站类的实例,但是本质上都是一样的代码,如果网站增多,实例也就增多,这对服务器资源浪费严重。
解决方法:具体数据和模板可以不同,但核心代码和数据库可以共享。
享元对象能做到共享的关键是区分内部状态和外部状态。
如:文本编辑器中通常将每一个字母做成一个享元对象。
享元的内部状态就是这个字母,字母在文本中的位置和子模风格等其他信息则是外部状态
虽然这些字母的位置和字模风格不同,但是所有这些地方使用的都是同一个字母对象。这样,字母对象就可以在整个系统中共享。
abstract class Flyweight//Flyweight类,它是所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态
{
public String intrinsic;//内部状态
protected final String extrinsic;//外部状态
//要求享元角色必须接受外部状态
public Flyweight(String extrinsic)
{
this.extrinsic=extrinsic;
}
public abstract void operate(int extrinsic);//定义业务操作
public String getIntrinsic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
}
class ConcreteFlyweight extends Flyweight//继承并为内部状态增加存储空间
{
public ConcreteFlyweight(String extrinsic)
{//接受外部状态
super(extrinsic);
}
//根据外部状态进行逻辑处理
@Override
public void operate(int extrinsic) {
// TODO Auto-generated method stub
System.out.println("具体Flyweight:"+extrinsic);
}
}
class UnsharedConcreteFlyweight extends Flyweight//指不需要共享的Flyweight子类,不强制共享。
{
public UnsharedConcreteFlyweight(String extrinsic)
{
super(extrinsic);
}
public void operate(int extrinsic) {
// TODO Auto-generated method stub
System.out.println("不共享的具体Flyweight:"+extrinsic);
}
}
class FlyweightFactory//享元工厂,用来创建并管理Flyweight对象,当用户请求一个Flyweight是,工厂对象提供一个已创建的实例或者创建一个。
{
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.print("已有"+extrinsic+"直接从池中取--->");
}else
{//根据外部状态创建享元对象
flyweight =new ConcreteFlyweight(extrinsic);
pool.put(extrinsic, flyweight);//放入池中
System.out.print("创建"+extrinsic+"并从池中取出--->");
}
return flyweight;
}
}
public class main
{
public static void main(String[] args) {
int extrinsic=22;
FlyweightFactory f=new FlyweightFactory();
Flyweight flyweightX=f.getFlyweight("X");
flyweightX.operate(--extrinsic);
Flyweight flyweightY=f.getFlyweight("Y");
flyweightY.operate(--extrinsic);
Flyweight flyweightZ=f.getFlyweight("Z");
flyweightZ.operate(--extrinsic);
Flyweight flyweightRex =f.getFlyweight("X");
flyweightRex.operate(--extrinsic);
Flyweight unsharedFlyweight = new UnsharedConcreteFlyweight("X");
unsharedFlyweight.operate(--extrinsic);
}
}
结果为:
创建X并从池中取出--->具体Flyweight:21
创建Y并从池中取出--->具体Flyweight:20
创建Z并从池中取出--->具体Flyweight:19
已有X直接从池中取--->具体Flyweight:18
不共享的具体Flyweight:17
FlyweightFactory根据客户需求返回生成好的对象,但实际上不一定需要事先生成对象的实例,完全可以初始化时什么也不做,到需要时,再去判断对象是否已经存在来决定是否实例化。
UnsharedConcreteFlyweight用来解决不需要共享对象的问题。
关于含有外部状态的共享网站代码
class User
{//外部状态,用户类
private String name;
User(String name)
{
this.name=name;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name=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 static HashMap<String,WebSite> flyweights=new HashMap<String,WebSite>();
//获得网站分类
public WebSite GetWebSiteCategory(String key)
{
if(!flyweights.containsKey(key))
{
WebSite 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) {
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());
}
}
结果为:
网站分类:产品展示用户:小菜
网站分类:产品展示用户:大鸟
网站分类:产品展示用户:娇娇
网站分类:博客用户:老顽童
网站分类:博客用户:桃谷六仙
网站分类:博客用户:南海神鳄
网站分类总数为2
享元模式设计的重点就在***分离变与不变***。把一个对象的状态分成内部状态和外部状态,内部状态是不变的,外部状态是可变的。然后通过共享不变的部分,达到减少对象数量节约内存。
享元模式使用情况:
- 一个系统有大量的对象
- 这些对象耗费大量的内存
- 这些对象的状态中的大部分都可以外部化
- 这些对象可以按照内部状态分成很多的组,当把外部对象从对象中剔除时,每一组都可以仅用一个对象代替。
优点:
降低内存中对象的数量,节省内存空间
缺点:
使得系统更加的复杂。将享元对象外部化,使运行时间变长。
本质
分离和共享