享元方式(Flyweight)
享元模式(Flyweight)
@@@模式定义:
运用共享技术有效地支持大量细粒度的对象。
@@@练习示例:
给系统加入权限控制
@@@示例代码:
[不使用模式的实现]
\usual\AuthorizationModel.java
\usual\TestDB.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\usual\SecurityMgr.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\user\ClientUsual.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
运行结果
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
am==usual.AuthorizationModel@c21495
am==usual.AuthorizationModel@1d5550d
am==usual.AuthorizationModel@c2ea3f
f1==false
f2==true
am==usual.AuthorizationModel@a0dcd9
am==usual.AuthorizationModel@186d4c1
am==usual.AuthorizationModel@f9f9d8
[存在的问题]
对象实例数目太多。
在系统当中,存在大量的细粒度对象,而且存在大量的重复数据,
严重耗费内存,如何解决?
[使用模式的实现]
\pattern\Flyweight.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\AuthorizationFlyweight.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\FlyweightFactory.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\TestDB.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\SecurityMgr.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\user\ClientPattern.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@@模式定义:
运用共享技术有效地支持大量细粒度的对象。
@@@练习示例:
给系统加入权限控制
@@@示例代码:
[不使用模式的实现]
\usual\AuthorizationModel.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package usual; /** * 描述授权数据的数据model */ public class AuthorizationModel { /** * 人员 */ private String user; /** * 安全实体 */ private String securityEntity; /** * 权限 */ private String permit; public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getSecurityEntity() { return securityEntity; } public void setSecurityEntity(String securityEntity) { this.securityEntity = securityEntity; } public String getPermit() { return permit; } public void setPermit(String permit) { this.permit = permit; } }
\usual\TestDB.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package usual; import java.util.ArrayList; import java.util.Collection; /** * 供测试用,在内存中模拟数据库中的值 */ public class TestDB { /** * 用来存放授权数据的值 */ public static Collection<String> colDB = new ArrayList<String>(); static { // 通过静态块来填充模拟的数据 colDB.add("张三,人员列表,查看"); colDB.add("李四,人员列表,查看"); colDB.add("李四,薪资数据,查看"); colDB.add("李四,薪资数据,修改"); // 增加更多的授权数据 for (int i = 0; i < 3; i++) { colDB.add("张三" + i + ",人员列表,查看"); } } }
\usual\SecurityMgr.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package usual; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * 安全管理,实现成单例 */ public class SecurityMgr { private static SecurityMgr securityMgr = new SecurityMgr(); private SecurityMgr() { } public static SecurityMgr getInstance() { return securityMgr; } /** * 在运行期间,用来存放登录人员对应的权限 * 在Web应用中,这些数据通常会存放到session中 */ private Map<String, Collection<AuthorizationModel>> map = new HashMap<String, Collection<AuthorizationModel>>(); /** * 模拟登录的功能 * @param user 登录的用户 */ public void login(String user) { // 登录时就需要把该用户所拥有的权限,从数据库中取出来,放到缓存中去 Collection<AuthorizationModel> col = queryByUser(user); map.put(user, col); } /** * 判断某用户对某个安全实体是否拥有某种权限 * @param user 被检测权限的用户 * @param securityEntity 安全实体 * @param permit 权限 * @return true表示拥有相应权限, false表示没有相应权限 */ public boolean hasPermit(String user, String securityEntity , String permit) { Collection<AuthorizationModel> col = map.get(user); if (col == null || col.size() == 0) { System.out.println(user + "没有登录或是没有被分配任何权限"); } for (AuthorizationModel am : col) { // 输出当前实例,看看是否同一个实例对象 System.out.println("am==" + am); if (am.getSecurityEntity().equals(securityEntity) && am.getPermit().equals(permit)) { return true; } } return false; } /** * 从数据库中获取某人所拥有的权限 * @param user 需要获取所拥有的权限的人员 * @return 某人所拥有的权限 */ private Collection<AuthorizationModel> queryByUser(String user) { Collection<AuthorizationModel> col = new ArrayList<AuthorizationModel>(); for (String s : TestDB.colDB) { String ss[] = s.split(","); if (ss[0].equals(user)) { AuthorizationModel am = new AuthorizationModel(); am.setUser(ss[0]); am.setSecurityEntity(ss[1]); am.setPermit(ss[2]); col.add(am); } } return col; } }
\user\ClientUsual.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package user; import usual.SecurityMgr; public class ClientUsual { public static void main(String[] args) { // 需要先登录,然后再判断是否有权限 SecurityMgr mgr = SecurityMgr.getInstance(); mgr.login("张三"); mgr.login("李四"); boolean f1 = mgr.hasPermit("张三", "薪资数据", "查看"); boolean f2 = mgr.hasPermit("李四", "薪资数据", "查看"); System.out.println("f1==" + f1); System.out.println("f2==" + f2); for (int i = 0; i < 3; i++) { mgr.login("张三" + i); mgr.hasPermit("张三" + i, "薪资数据", "查看"); } } }
运行结果
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
am==usual.AuthorizationModel@c21495
am==usual.AuthorizationModel@1d5550d
am==usual.AuthorizationModel@c2ea3f
f1==false
f2==true
am==usual.AuthorizationModel@a0dcd9
am==usual.AuthorizationModel@186d4c1
am==usual.AuthorizationModel@f9f9d8
[存在的问题]
对象实例数目太多。
在系统当中,存在大量的细粒度对象,而且存在大量的重复数据,
严重耗费内存,如何解决?
[使用模式的实现]
\pattern\Flyweight.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern; /** * 描述授权数据的享元接口 */ public interface Flyweight { /** * 判断传入的安全实体和授权,是否和享元对象内部状态匹配 * * @param securityEntity * 安全实体 * @param permit * 权限 * @return true表示匹配, false表示不匹配 */ public boolean match(String securityEntity, String permit); }
\pattern\AuthorizationFlyweight.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern; /** * 封装授权数据中重复出现部分的享元对象 */ public class AuthorizationFlyweight implements Flyweight { /** * 内部状态,安全实体 */ private String securityEntity; /** * 内部状态,权限 */ private String permit; /** * 构造方法,传入状态数据 * * @param state * 状态数据,包含安全实体和权限的数据,用","分隔 */ public AuthorizationFlyweight(String state) { String ss[] = state.split(","); securityEntity = ss[0]; permit = ss[1]; } public String getSecurityEntity() { return securityEntity; } public String getPermit() { return permit; } @Override public boolean match(String securityEntity, String permit) { if (this.securityEntity.equals(securityEntity) && this.permit.equalsIgnoreCase(permit)) { return true; } return false; } }
\pattern\FlyweightFactory.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern; import java.util.HashMap; import java.util.Map; /** * 享元工厂,通常实现成为单例 */ public class FlyweightFactory { private static FlyweightFactory factory = new FlyweightFactory(); private FlyweightFactory() { } public static FlyweightFactory getInstance() { return factory; } /** * 缓存多个Flyweight对象 */ private Map<String, Flyweight> fsMap = new HashMap<String, Flyweight>(); /** * 获取key对应的享元对象 * @param key 获取享元对象的key * @return 对应的享元对象 */ public Flyweight getFlyweight(String key) { Flyweight f = fsMap.get(key); if (f == null) { f = new AuthorizationFlyweight(key); fsMap.put(key, f); } return f; } }
\pattern\TestDB.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern; import java.util.ArrayList; import java.util.Collection; /** * 供测试用,在内存中模拟数据库中的值 */ public class TestDB { /** * 用来存放授权数据的值 */ public static Collection<String> colDB = new ArrayList<String>(); static { // 通过静态块来填充模拟的数据 colDB.add("张三,人员列表,查看"); colDB.add("李四,人员列表,查看"); colDB.add("李四,薪资数据,查看"); colDB.add("李四,薪资数据,修改"); // 增加更多的授权数据 for (int i = 0; i < 3; i++) { colDB.add("张三" + i + ",人员列表,查看"); } } }
\pattern\SecurityMgr.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * 安全管理,实现成单例 */ public class SecurityMgr { private static SecurityMgr securityMgr = new SecurityMgr(); private SecurityMgr() { } public static SecurityMgr getInstance() { return securityMgr; } /** * 在运行期间,用来存放登录人员对应的权限 * 在Web应用中,这些数据通常会存放到session中 */ private Map<String, Collection<Flyweight>> map = new HashMap<String, Collection<Flyweight>>(); /** * 模拟登录的功能 * @param user 登录的用户 */ public void login(String user) { // 登录时就需要把该用户所拥有的权限,从数据库中取出来,放到缓存中去 Collection<Flyweight> col = queryByUser(user); map.put(user, col); } /** * 判断某用户对某个安全实体是否拥有某种权限 * @param user 被检测权限的用户 * @param securityEntity 安全实体 * @param permit 权限 * @return true表示拥有相应权限, false表示没有相应权限 */ public boolean hasPermit(String user, String securityEntity , String permit) { Collection<Flyweight> col = map.get(user); if (col == null || col.size() == 0) { System.out.println(user + "没有登录或是没有被分配任何权限"); } for (Flyweight fm : col) { // 输出当前实例,看看是否同一个实例对象 System.out.println("fm==" + fm); if (fm.match(securityEntity, permit)) { return true; } } return false; } /** * 从数据库中获取某人所拥有的权限 * @param user 需要获取所拥有的权限的人员 * @return 某人所拥有的权限 */ private Collection<Flyweight> queryByUser(String user) { Collection<Flyweight> col = new ArrayList<Flyweight>(); for (String s : TestDB.colDB) { String ss[] = s.split(","); if (ss[0].equals(user)) { Flyweight fs = FlyweightFactory.getInstance() .getFlyweight(ss[1] + "," + ss[2]); col.add(fs); } } return col; } }
\user\ClientPattern.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package user; import pattern.SecurityMgr; public class ClientPattern { public static void main(String[] args) { // 需要先登录,然后再判断是否有权限 SecurityMgr mgr = SecurityMgr.getInstance(); mgr.login("张三"); mgr.login("李四"); boolean f1 = mgr.hasPermit("张三", "薪资数据", "查看"); boolean f2 = mgr.hasPermit("李四", "薪资数据", "查看"); System.out.println("f1==" + f1); System.out.println("f2==" + f2); for (int i = 0; i < 3; i++) { mgr.login("张三" + i); mgr.hasPermit("张三" + i, "薪资数据", "查看"); } } }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fm==pattern.AuthorizationFlyweight@c2ea3f
fm==pattern.AuthorizationFlyweight@c2ea3f
fm==pattern.AuthorizationFlyweight@a0dcd9
f1==false
f2==true
fm==pattern.AuthorizationFlyweight@c2ea3f
fm==pattern.AuthorizationFlyweight@c2ea3f
fm==pattern.AuthorizationFlyweight@c2ea3f
@@@模式的实现:
享元模式设计的重点就在于分离变与不变。
把一个对象的状态分为不可变的内部状态和可变的外部状态。
然后通过共享不变的部分,达到减少对象数量并节约内存的目的。
@@@模式的优点:
减少对象数量,节省内存空间。
@@@模式的缺点:
维护共享对象,需要额外内存。
@@@模式的本质:
分离与共享。
@@@模式体现的设计原则:
NA