声明:
本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/*
* 个人理解:
* 1、Flyweight模式其实就是缓存:把公用的、可共享的数据缓存(示例里面把数据存放在一个单例的Map里面)
* 2、不需共享的享元对象:因为这些对象是Flyweight的组合,Flyweight已经共享了,就不需要重复缓存了
* 例如:操作薪资数据=查看薪资数据+修改薪资数据
*/
/**
* Flyweight模式的主要原理就在这里
* 假设要描述“张三拥有薪资数据的查看权限”“李四拥有薪资数据的查看权限”,“王五拥有薪资数据的查看权限”……
* 我们很容易看出,“薪资数据的查看权限”是可共享的。我们把它定义为IFlyweight接口,并将它缓存在一个HashMap里面:
*/
enum FlyweightFactory {
INSTANCE;
//Map<"薪资数据,查看",IFlyweight(entity="薪资数据",permission="查看")>
private Map<String, IFlyweight> flyweightMap = new HashMap<String, IFlyweight>();
public IFlyweight getFlyweight(String state) {
IFlyweight flyweight = flyweightMap.get(state);
if (flyweight == null) {
flyweight = new AuthorizationFlyweight(state);
flyweightMap.put(state, flyweight);
}
return flyweight;
}
}
//要共享的数据-接口
interface IFlyweight {
/**
* 验证是否对该“安全实体”有权限
* @param securityEntity 安全实体,即需要保证安全的数据,访问时要做访问控制,例如,工资数据
* @param permission 权限描述,例如:查看、修改等等
* @return true 表示通过 false表示不通过
*/
boolean testify(String securityEntity, String permission);
//这个方法是提供给“不需共享的对象”的。“共享对象”不支持这个方法(throw unsupportException)
void add(IFlyweight flyweight);
//返回Flyweight的描述
String getDescription();
}
//要共享的数据-具体实现类
class AuthorizationFlyweight implements IFlyweight {
private String securityEntity;
private String permission;
public boolean testify(String securityEntity, String permission) {
return this.securityEntity.equals(securityEntity)
&& this.permission.equals(permission);
}
//e.g. state="薪资数据,查看"
public AuthorizationFlyweight(String state) {
String[] states = state.split(",");
this.securityEntity = states[0];
this.permission = states[1];
}
public String getSecurityEntity() {
return securityEntity;
}
public String getPermission() {
return permission;
}
public void add(IFlyweight flyweight) {
throw new UnsupportedOperationException("对象不支持此功能");
}
public String getDescription() {
return permission + securityEntity;
}
}
//不需共享的数据
class UnsharedFlyweight implements IFlyweight {
//保存了一系列的“共享对象”
private List<IFlyweight> list = new ArrayList<IFlyweight>();
public void add(IFlyweight flyweight) {
list.add(flyweight);
}
public boolean testify(String securityEntity, String permission) {
for (IFlyweight flyweight : list) {
if (flyweight.testify(securityEntity, permission)) {
return true;
}
}
return false;
}
public String getDescription() {
StringBuilder sb = new StringBuilder("(组合权限 ");
for (IFlyweight flyweight : list) {
sb.append(flyweight.getDescription()).append("=").append(flyweight).append(" ");
}
sb.append(")\n");
return sb.toString();
}
}
enum SecurityManagement {
INSTANCE;
//Map<用户名,用户权限> 在web应用中,这些数据通常存放在session中
private Map<String, Collection<IFlyweight>> userPermissionMap = new HashMap<String, Collection<IFlyweight>>();
//登录时查询并缓存用户拥有的权限
public void login(String user) {
Collection<IFlyweight> permissions = this.getPermissionsOf(user);
userPermissionMap.put(user, permissions);
}
//begin-只测试“共享”
private Collection<IFlyweight> getPermissionsOf(String user) {
Collection<IFlyweight> permissions = new ArrayList<IFlyweight>();
for (String data : TestDB.dataList) {
String[] datas = data.split(",");
String userName = datas[0];
String securityEntity = datas[1];
String permission = datas[2];
if (userName.equals(user)) {
String state = securityEntity + "," + permission;
//从缓存中取数据。如果缓存中没有,就把这个数据保存在缓存中
IFlyweight flyweight = FlyweightFactory.INSTANCE.getFlyweight(state);
permissions.add(flyweight);
}
}
return permissions;
}
public void login2(String user) {
Collection<IFlyweight> permissions = this.getPermissionsOf2(user);
userPermissionMap.put(user, permissions);
}
//end
//begin-同时测试“共享”和“不共享”
private Collection<IFlyweight> getPermissionsOf2(String user) {
Collection<IFlyweight> permissions = new ArrayList<IFlyweight>();
for (String data : TestDB2.dataList) {
String[] datas = data.split(",");
String userName = datas[0];
String securityEntity = datas[1];
String permission = datas[2];
String type = datas[3];
if (userName.equals(user)) {
IFlyweight flyweight = null;
String state = null;
if (type.equals("2")) { //表示是组合类型的授权
state = securityEntity + permission;
flyweight = new UnsharedFlyweight();
String[] composites = TestDB2.dataMap.get(state);
for (String composite : composites) {
//“共享对象”的组合。“共享对象”从缓存中取出
IFlyweight singleFlyweight = FlyweightFactory.INSTANCE.getFlyweight(composite);
flyweight.add(singleFlyweight);
}
} else {
state = securityEntity + "," + permission;
flyweight = FlyweightFactory.INSTANCE.getFlyweight(state);
}
permissions.add(flyweight);
}
}
return permissions;
}
//end
public boolean hasPermission(String user, String securityEntity, String permission) {
System.out.println("现在验证:"+ user + securityEntity + permission);
boolean result = false;
Collection<IFlyweight> flyweightCollection = userPermissionMap.get(user);
if (flyweightCollection == null || flyweightCollection.size() == 0) {
System.out.println(user + "没有登陆或是没有分配任何权限");
result = false;
} else {
System.out.println("拥有的权限:");
for (IFlyweight flyweight : flyweightCollection) {
System.out.println(flyweight.getDescription()+ ";flyweight = " + flyweight);
if (flyweight.testify(securityEntity, permission)) {
result = true;
break;
}
}
}
return result;
}
}
//数据库1-共享
class TestDB{
public static Collection<String> dataList = new ArrayList<String>();
static {
dataList.add("张三,人员列表,查看");
dataList.add("李四,人员列表,查看 ");
dataList.add("李四,薪资数据,查看");
dataList.add("李四,薪资数据,修改");
dataList.add("张三1,人员列表,查看");
dataList.add("张三2,人员列表,查看");
dataList.add("张三3,人员列表,查看");
}
}
//数据库2-同时有共享和不共享的数据。增加了一个字段表示权限类型是单个权限(1)还是组合权限(2)
class TestDB2{
public static Collection<String> dataList = new ArrayList<String>();
public static Map<String, String[]> dataMap = new HashMap<String, String[]>();
static {
dataList.add("张三,人员列表,查看,1");
dataList.add("张三1,人员列表,查看,1");
dataList.add("张三2,人员列表,查看,1");
dataList.add("张三3,人员列表,查看,1");
dataList.add("李四,人员列表,查看,1");
dataList.add("李四,薪资数据,查看,1"); //a
dataList.add("李四,薪资数据,修改,1"); //b (a+b刚好是“薪资数据操作”;实际应用中不应该这样存储)
dataList.add("张三,薪资数据,操作,2");
dataMap.put("薪资数据操作", new String[]{"薪资数据,查看","薪资数据,修改"});
}
}
//这个类是用来测试的
public class FlyweightPattern {
public static void main(String[] args) {
SecurityManagement securityManagement = SecurityManagement.INSTANCE;
/*//测试“共享”
securityManagement.login("张三");
securityManagement.login("张三1");
securityManagement.login("张三2");
securityManagement.login("张三3");
securityManagement.login("李四");
boolean b1 = securityManagement.hasPermission("张三", "薪资数据", "查看");
boolean b2 = securityManagement.hasPermission("李四", "薪资数据", "查看");
System.out.println(b1 + "," + b2);
//可以看到下面这四句,输出flyweight时,是同一个flyweight,表明缓存被使用了
System.out.println(securityManagement.hasPermission("张三", "人员列表", "查看"));
System.out.println(securityManagement.hasPermission("张三1", "人员列表", "查看"));
System.out.println(securityManagement.hasPermission("张三2", "人员列表", "查看"));
System.out.println(securityManagement.hasPermission("张三3", "人员列表", "查看"));
*/
//测试“共享”和“不共享的对象”
securityManagement.login2("张三");
securityManagement.login2("张三1");
securityManagement.login2("张三2");
securityManagement.login2("张三3");
securityManagement.login2("李四");
//可以看到,张三“薪资数据操作”所包含的“薪资数据查看”、“薪资数据修改”这两个flyweight与李四的是同一对象
System.out.println(securityManagement.hasPermission("张三", "薪资数据", "修改"));
System.out.println(securityManagement.hasPermission("张三", "薪资数据", "查看"));
System.out.println(securityManagement.hasPermission("李四", "薪资数据", "修改"));
System.out.println(securityManagement.hasPermission("李四", "薪资数据", "查看"));
System.out.println(securityManagement.hasPermission("李四", "人员列表", "修改"));
//不能直接测试“操作”
//System.out.println(securityManagement.hasPermission("张三", "薪资数据", "操作"));
}
}