享元模式
1、概念
1)解决场景
需要在系统中增加类和对象个数。当对象数量太多时,将导致运行代价过高,带来性能下降等问题。
2)概念
享元模式(Flyweight Pattern)又称轻量级模式,是对象池的一种实现。类似于线程池,线程池可以不停的创建和销毁多个对象,消耗性能。提供了减少对象数量从而改善应用所需的对象结构的方式。其宗旨是共享细颗粒度对象,将多个对同一对象的访问几种起来,不必为每个访问者创建一个单独的对象,以此来降低内存的消耗。
3)原理
享元模式把一个对象的状态分成内部状态和外部状态,内部状态即是不变的,外部状态是变化的;然后通过共享不变的部分,达到减少对象数量并节约内存的目的。
享元模式的本质是缓存共享对象,降低内存消耗。
4)角色
抽象享元角色(IFlyweight)
享元对象抽象基类或者接口,同时定义出对象的外部状态和内部状态的接口或者实现;
具体享元角色(ConcreteFlyweight)
实现抽象角色定义的业务。该角色的内部状态处理应该与环境无关,不能出现会有一个操作改变内部状态 ,同时修改了外部状态;
享元工厂(FlyweightFactory)
负责管理享元对象池和创建享元对象。
5)内部状态和外部状态
享元模式的定义为我们提出了两个要求:细粒度和共享对象。因为要求细粒度对象 ,所以不可避免地会使对象数量多且性质相近 ,此时我们就将这些对象的信息分为两个部分:内部状态和外部状态。
内部状态指对象共享出来的信息 ,存储在享元对象内部并且不会随环境的改变而改变;外部状态指对象得以依赖的一个标记 ,是随环境改变而改变的、不可共享的状态。
比如 ,连接池中的连接对象 ,保存在连接对象中的用户名、密码、连接url等信息 ,在创建对象的时候就设置好了 ,不会随环境的改变而改变 ,这些为内部状态。而每个连接要回收利用时 ,我们需要给它标记为可用状态 ,这些为外部状态。
2、使用
1)代码实现
抽象享元角色(IFlyweight)
package com.csk.mode.flyweightPattern.domain;
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
package com.csk.mode.flyweightPattern.service;
import com.csk.mode.flyweightPattern.domain.User;
public interface WebSite {
void use(User user);
}
具体享元角色(ConcreteFlyweight)
package com.csk.mode.flyweightPattern.service.impl;
import com.csk.mode.flyweightPattern.domain.User;
import com.csk.mode.flyweightPattern.service.WebSite;
public class ConcreteWebSite implements WebSite {
private String name = "";
public ConcreteWebSite(String name) {
this.name = name;
}
@Override
public void use(User user) {
System.out.println("网站分类: " + name + ";用户:" + user.getName());
}
}
享元工厂(FlyweightFactory)
package com.csk.mode.flyweightPattern.factory;
import com.csk.mode.flyweightPattern.service.WebSite;
import com.csk.mode.flyweightPattern.service.impl.ConcreteWebSite;
import java.util.Hashtable;
public class WebSiteFactory {
private Hashtable flyweights = new Hashtable();
// 获得网站分类
public WebSite getWebSiteCategory(String key){
if(!flyweights.containsKey(key)){
flyweights.put(key, new ConcreteWebSite(key));
}
return (WebSite) flyweights.get(key);
}
// 获取网站分类总数
public int getWebSiteCount(){
return flyweights.size();
}
}
启动类
package com.csk.mode.flyweightPattern.controller;
import com.csk.mode.flyweightPattern.domain.User;
import com.csk.mode.flyweightPattern.factory.WebSiteFactory;
import com.csk.mode.flyweightPattern.service.WebSite;
public class FlyweightPatternMain {
public static void main(String[] args) {
WebSiteFactory webSiteFactory = new WebSiteFactory();
WebSite fx = webSiteFactory.getWebSiteCategory("产品展示");
fx.use(new User("雨哥"));
WebSite fy = webSiteFactory.getWebSiteCategory("产品展示");
fy.use(new User("旭哥"));
WebSite fz = webSiteFactory.getWebSiteCategory("产品展示");
fz.use(new User("凯哥"));
WebSite fl = webSiteFactory.getWebSiteCategory("博客");
fl.use(new User("刘雨"));
WebSite fm = webSiteFactory.getWebSiteCategory("博客");
fm.use(new User("张旭策"));
WebSite fn = webSiteFactory.getWebSiteCategory("博客");
fn.use(new User("陈书凯"));
System.out.println("网站分类总数为:" + webSiteFactory.getWebSiteCount());
}
}
截图
2)使用场景
常常应用于系统底层的开发,以便解决系统的性能问题;
系统有大量相似的对象、需要缓存池的场景;
3)优缺点
优点
减少对象的创建 ,降低内存中对象的数量 ,降低系统的内存 ,提高效率;减少内存之外的其它资源占用。
缺点
关注内、外部状态、关注线程安全问题;使系统、程序复杂化。