JAVA设计模式之享元模式

Java 设计模式 之 享元模式(Flyweight)

享元模式的重点在于分离变不变。把一个对象的状态分成内部状态外部状态内部状态不变的,外部状态可变的。然后通过共享不变的部分,达到减少对象数量节约内存的目的。

内部状态:通常指的是包含在享元对象内部的、对象本身的状态,不会随享元环境而变化,因此可共享。

外部状态:是享元对象之外的状态,取决于使用享元的场景,会根据使用场景而变化,因此不可共享。如果享元对象需要这些外部状态的话,可以从外部传到外部状态中。

外部状态和内部状态是相互独立的,外部状态的变换不会因起内部状态的变化。

享元对象的优点:减少对象数量,节省内存空间。

享元模式的缺点:维护共享对象,需要额外的开销(用一个线程来维护垃圾回收)。

享元模式的本质:分离与共享。

何时使用享元对象:

● 如果一个应用程序使用了大量的细粒度对象,可以使用享元模式来减少对象数量。

● 如果使用大量的对象,造成很大的存储开销,可以使用享元模式来减少对象数量,并节约内存。

● 如果对象的大多数状态都可以转变为外部状态,可以使用享元对象来实现外部状态与内部状态的分离。

Flyweight :享元接口,通过这个接口可以接受并作用于外部状态。通过这个接口传入外部的状态。

ConcreteFlyweight :具体的享元实现对象,必须是可共享的,需要封装享元对象的内部状态。

UnsharedConcreteFlyweight :非共享的享元实现对象,并不是所有的享元对象都可以共享,非共享的享元对象通常是享元对象的组合对象。

FlyweightFactory :享元工厂,主要用来创建并管理共享的享元对象,并对外提供访问共享享元的接口。

样例

/**

* 享元接口

*/

public interface Flyweight {

/**
* 判断传入的安全实体和权限,是否和享元对象内部状态匹配
* @param securityEntity
* @param permit
* @return
*/
public booleanmatch(String securityEntity, String permit);
}

/**

* 享元对象

*/

public classAuthorizationFlyweight implementsFlyweight {

/**
* 内部状态,安全实体
*/
privateString securityEntity;
/**
* 内部状态,权限
*/
privateString permit;

publicAuthorizationFlyweight(String state) {
String ss[] = state.split(",");
this.securityEntity = ss[0];
this.permit = ss[1];
}

@Override
public booleanmatch(String securityEntity, String permit) {
if(this.securityEntity.equals(securityEntity) &&this.permit.equals(permit)){
return true;
}
return false;
}

publicString getSecurityEntity() {
returnsecurityEntity;
}

publicString getPermit() {
returnpermit;
}
}

/**
* 享元工厂,通常实现为单例
*
*/
public classFlyweightFactory {

private staticFlyweightFactory factory= new FlyweightFactory();

privateFlyweightFactory(){

}

public staticFlyweightFactory getInstance(){
return factory;
}

/**
* 缓存多个Flyweight对象
*/
privateMap<String, Flyweight> fsMap = newHashMap<String, Flyweight>();
/**
* 获取享元对象
* @param key
* @return
*/
publicFlyweight getFlyweight(String key) {
Flyweight f = fsMap.get(key);
if(f ==null){
f =new AuthorizationFlyweight(key);
fsMap.put(key, f);
}
returnf;
}

}

/**
* 安全管理器,实现成单例
*
*/
public classSecurityMgr {

private staticSecurityMgr securityMgr= new SecurityMgr();

privateSecurityMgr(){

}

public staticSecurityMgr getInstance() {
returnsecurityMgr;
}
/**
* 在运行期间,用来存放登陆人员对应的权限
* 在Web应用中,这些数据通常存放到session中
*/
privateMap<String, Collection<Flyweight>> map = new HashMap<String, Collection<Flyweight>>();
/**
* 登陆功能
* @param user
*/
public voidlogin(String user) {
Collection<Flyweight> col = queryByUser(user);
map.put(user, col);
}
/**
* 从数据库中获取某人所拥有的权限
* @param user
* @return
*/
privateCollection<Flyweight> queryByUser(String user) {
Collection<Flyweight> col =new ArrayList<Flyweight>();
for(String s : TestDB.colDB){
String ss[] = s.split(",");
if(ss[0].equals(user)){
//ss[0] - user
//ss[1] - securityEntity
//ss[2] - permit
Flyweight fm = FlyweightFactory.getInstance().getFlyweight(ss[1]+","+ss[2]);
col.add(fm);
}
}
returncol;
}
/**
* 判断用户对某个安全实体是否拥有某种权限
* @param user 用户
* @param securityEntity 安全实体
* @param permit 权限
* @return
*/
public booleanhasPermit(String user, String securityEntity, String permit){
Collection<Flyweight> col = map.get(user);
if(col ==null || col.size() == 0){
System.out.println(user + "没有登陆或没有被分配任何权限");
return false;
}
for(Flyweight fm : col) {
System.out.println("fm == " + fm);
if(fm.match(securityEntity, permit)){
return true;
}
}
return false;
}
}

/**
* 测试使用,在内存中存放模拟数据库的值
*
*/
public classTestDB {

public staticCollection<String> colDB= new ArrayList<String>();

static{
colDB.add("张三,人员列表,查看");
colDB.add("李四,人员列表,查看");
colDB.add("李四,薪资列表,查看");
colDB.add("李四,薪资列表,修改");

for(inti = 0; i < 3; i++){
colDB.add("张三" + i + ",人员列表,查看");
}
}
}


public class Client {

public static voidmain(String[] args) {
SecurityMgr mgr = SecurityMgr.getInstance();
mgr.login("张三");
mgr.login("李四");

booleanf1 = mgr.hasPermit("张三", "薪资列表", "查看");
booleanf2 = mgr.hasPermit("李四", "薪资列表", "查看");
booleanf3 = mgr.hasPermit("张三", "人员列表", "查看");

System.out.println("f1 == " + f1);
System.out.println("f2 == " + f2);
System.out.println("f3 == " + f3);

for(inti = 0; i < 3; i++){
mgr.login("张三" + i);
mgr.hasPermit("张三" + i, "薪资列表", "查看");
}

posted @ 2012-12-07 07:52  yangkai_keven  阅读(161)  评论(0编辑  收藏  举报