读《研磨设计模式》-代码笔记-享元模式-Flyweight

声明:
本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客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("张三", "薪资数据", "操作"));
		
	}

}


你可能感兴趣的:(java,设计模式)