享元模式的定义:用共享的技术有效地支持大量细粒度的对象。
认识享元模式:
1、变与不变
享元模式的设计重点就在于分享变与不变。把一个对象分离为内部状态和外部状态,内部状态是不变的,外部状态是可变的。然后通过共享不变的部分,以达到节约空间的目的。
2、共享与不共享
在享元模式中,又有共享和不共享之分。有时还可以把共享的享元对象组合成一个组合对象,这样的组合对象可以不用共享,需要时创建他就可以了。
3、内部状态和外部状态
内部状态是享元对象内部的属性、状态,是不变的,所以可以共享。
外部状态是享元对象外部的状态,取决于使用的场景,会根据使用场景而变化,所以不可以共享。
4、实例池
在享元模式中,会创建一个享元工厂,用它来管理、创建和清理享元对象。享元对象就缓存在这个工厂中。这个享元工厂的难度在于何时清理不再需要或者是长时间不再需要的享元对象,可以选择使用长时间不用的享元对象,就把它清理掉。
示例代码:
1、示例说明:
这里有两个名词:(1)安全实体:就是被权限系统检测的对象,如“工资数据”;(2)权限:就是要被校验的权限对象。如“查看”和“编辑”。
此示例是一个模拟登录后,用户有不同的系统访问权限。当用户登录后,会将用户的权限保存到系统内存中或web程序的Session中。但是系统为了节约不变的对象,
便可用享元模式去保存相同的对象。如:
张三有“查看”“工资数据”的权限。
李四有“查看”“工资数据”的权限。
《“查看”“工资数据”的权限》,不同的人都可以有这个权限,但并不需要为每个人都实例化一个这样的权限对象,将这个对象保存到内存中,以避免用户每次操作都去检查是否有权限。
为了节约空间,便可把这样不变的对象设置成享元对象,让所有的用户共享。
这样,用户登录后,将权限保存到享元工厂中。用户每次到享元工厂中拿对应的权限比对,检查是否有权限做对应的操作。
(1)享元接口
package gof.flyweight; /** * <p> * 享元接口 * </p> * * @author andy */ public interface Flyweight { boolean match(String security, String permit); }
(2)享元对象的实现
package gof.flyweight; /** * <p> * 享元对象的实现 * </p> * * @author andy * */ public class AuthorizationFlyweight implements Flyweight { /** * 内部状态,安全实体 */ private String security = "";; /** * 内部状态,权限 */ private String permit = "";; /** * @return the security */ public String getSecurity() { return security; } /** * @return the permit */ public String getPermit() { return permit; } public AuthorizationFlyweight(String state) { String[] data = state.split(","); if (data.length == 2) { this.security = data[0]; this.permit = data[1]; } } @Override public boolean match(String security, String permit) { if (this.security.equals(security) && this.permit.equals(permit)) { return true; } return false; } }
(3)享元对象的管理工厂
package gof.flyweight; import java.util.HashMap; import java.util.Map; /** * <p> * 享元对象的管理工厂 * </p> * * @author andy * */ public class FlyweightFactory { /** * 缓存享元实例 */ private Map<String, Flyweight> flyweightMap = new HashMap<String, Flyweight>(); private static FlyweightFactory instance = new FlyweightFactory(); private FlyweightFactory() { } public static FlyweightFactory getInstance() { return instance; } public Flyweight getFlyweight(String key) { Flyweight result = null; result = flyweightMap.get(key); if (result == null) { Flyweight f = new AuthorizationFlyweight(key); flyweightMap.put(key, f); result = f; } return result; } }
(4)处理用户请求
package gof.flyweight; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; /** * <p> * 安全管理 * </p> * * @author andy * */ public class SecurityManager { private static SecurityManager instance = new SecurityManager(); // 存储用户对应的仅限 private Map<String, Collection<Flyweight>> map = new HashMap<String, Collection<Flyweight>>(); private SecurityManager() { } public static SecurityManager getInstance() { return instance; } public void login(String user) { Collection<Flyweight> securitys = querySecurityByUser(user); map.put(user, securitys); } private Collection<Flyweight> querySecurityByUser(String user) { List<Flyweight> result = new ArrayList<Flyweight>(); for (String strs : TestDB.cols) { String[] str = strs.split(","); if (str[0].equals(user)) { result.add(FlyweightFactory.getInstance().getFlyweight(str[1] + "," + str[2])); } } return result; } public boolean hasPermit(String user, String security, String permit) { boolean result = false; Collection<Flyweight> flys = map.get(user); if (flys == null) { return false; } for (Flyweight f : flys) { if (f.match(security, permit)) { System.out.println("享元对象flyweight=" + f); result = true; break; } } return result; } }
(5)模拟DB数据
package gof.flyweight; import java.util.ArrayList; import java.util.Collection; /** * <p> * 模拟DB数据 * </p> * * @author andy * */ public class TestDB { public static Collection<String> cols = new ArrayList<String>(); static { cols.add("张三,人员列表,查看"); cols.add("张三,薪资结构,查看"); cols.add("李四,人员列表,查看"); cols.add("李四,薪资结构,编辑"); cols.add("李四,人员列表,编辑"); for (int i = 0; i < 3; i++) { cols.add("张三" + i + ",薪资结构,查看"); } } }