例题:有多个客户想要使用同样的网站但要求不太一样,有的希望是博客形式的,有的希望是产品图片说明形式的。
简单代码实现:
//网站类
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();
}
}
结果:
网站分类:产品展示
网站分类:产品展示
网站分类:产品展示
网站分类:博客
网站分类:博客
网站分类:博客
存在问题:如果网站增多,实例也增多,这对服务器的资源浪费得很严重。
解决方案:大网站里的各个小网站具体数据和模板可以不同,但核心代码和数据库却是共享的。
享元模式:运用共享技术有效地支持大量细粒度的对象。
享元对象能做到共享的关键是区分内部状态(InternalState)和外部状态(External State)。
内部状态:存储在享元对象内部并且不会随环境改变而改变。因此内部状态可以共享。
外部状态:随环境改变而改变的、不可以共享的状态。享元对象的外部状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。
外部状态与内部状态是相互独立的。
1、ConcreteFlyweight继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间。
2、UnsharedConcrefeFlweght是指那些不需要共享的FlyWeight子类,因为FlyWeight接口,使共享成为可能,但它不强制共享,它解决了那些不需要共享对象的问题。
3、FlyweightFactory是一个享元工厂,用来创建并管理Flyweight对象。它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时, FlyweightFactory对象提供一个已创建的实例或者创建一个新的实例。
import java.util.HashMap;
abstract class Flyweight{//所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态。
public String intrinsic;//内部状态
protected final String extrinsic;//外部状态
//要求享元角色必须接受外部状态
public Flyweight(String extrinsic) {
this.extrinsic=extrinsic;
}
public abstract void operate(int extrinsic);//定义业务操作
public String getIntrisic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic=intrinsic;
}
}
//ConcreteFlyweight继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间。
class ConcreteFlyweight extends Flyweight{
//接受外部状态
public ConcreteFlyweight(String extrinsic) {
super(extrinsic);
// TODO Auto-generated constructor stub
}
//根据外部状态进行逻辑处理
public void operate(int extrinsic) {
System.out.println("具体Flyweight:"+extrinsic);
}
}
//UnsharedConcreteFlyweight是指那些不需要共享的Flyweight子类。因为Flyweight接口使共享成为可能,但他并不强制共享。
class UnsharedConcreteFlyweight extends Flyweight{
public UnsharedConcreteFlyweight(String extrinsic) {
super(extrinsic);
}
@Override
public void operate(int extrinsic) {
// TODO Auto-generated method stub
System.out.println("不共享的具体Flyweight:"+extrinsic);
}
}
//FlyweightFactory,是一个享元工厂,用来创建并管理Flyweight对象。它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。
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);
pool.put(extrinsic, flyweight);//放入池中
System.out.println("创建"+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
网站共享代码(无外部状态的享元模式)
import java.util.HashMap;
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 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();
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
存在问题:这样写没有体现对象间的不同。
解决方案
import java.util.HashMap;
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);
}//参数user是在类WebSite外定义的一个类User,在方法Use调用时将它传递进来。
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
享元模式设计的重点就在分离变与不变。把一个对象的状态分成内部状态和外部状态,内部状态是不变的,外部状态是可变的。然后通过共享不变的部分,达到减少对象数量并节约内存的目的。
享元模式在什么情况下使用?
1、一个系统有大量的对象。
2、这些对象耗费大量的内存。
3、这些对象的状态中的大部分都可以外部化。
4、这些对象可以按照内部状态分成很多的组,当把外部对象从对象中剔除时,每一个组都可以仅用一个对象代替。