分享

java设计模式———享元模式

 李副营长 2014-01-09

享元模式的结构

  享元模式采用一个共享来避免大量拥有相同内容对象的开销。这种开销最常见、最直观的就是内存的损耗。享元对象能做到共享的关键是区分内蕴状态(Internal State)

外蕴状态(External State)。

  一个内蕴状态是存储在享元对象内部的,并且是不会随环境的改变而有所不同。因此,一个享元可以具有内蕴状态并可以共享。

  一个外蕴状态是随环境的改变而改变的、不可以共享的。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外

蕴状态不可以影响享元对象的内蕴状态,它们是相互独立的。

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

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

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

        何时使用享元模式:

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

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

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


  享元模式可以分成单纯享元模式复合享元模式两种形式。

单纯享元模式  

  在单纯的享元模式中,所有的享元对象都是可以共享的。
  单纯享元模式所涉及到的角色如下:
  抽象享元(Flyweight)角色 :给出一个抽象接口,以规定出所有具体享元角色需要实现的方法。


  具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定出的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。


  享元工厂(FlyweightFactory)角色 :本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的

时候,享元工厂角色会检查系统中是否 已经有一个符合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象

的话,享元工厂角色就应当创 建一个合适的享元对象。

        好了,废话不多说,直接上代码,首先抽象一个场景:

        公司的管理层和普通员工对员工的信息有不同的权限。管理层可以修改员工的个人信息,普员工只能查看不能修改,擅自修改系统会给出提示。员工的个人信息是可以共享的,但是起职能范围和操作权限可以被管理层修改。

抽象享元角色:

[java]
  1. public interface IFlyWeight {  
  2.       
  3.     /** 
  4.     * 判断传入的安全实体和权限,是否和享元对象内部状态匹配 
  5.     * 参数 securityEntity 和 permit 是外蕴对象 
  6.     * @param securityEntity  
  7.     * @param permit 
  8.     * @return 
  9.     */  
  10.     public boolean match(String securityEntity, String permit);  
  11.   
  12. }  

具体享元角色:

[java]
  1. public class AuthorizationFlyweight implements IFlyWeight {  
  2.     /** 
  3.      * 内蕴对象,安全实体 
  4.      */  
  5.     private String mSecurityEntity;  
  6.     /** 
  7.      * 内蕴对象,权限 
  8.      */  
  9.     private String mPermit;  
  10.   
  11.     public AuthorizationFlyweight(String state) {  
  12.         String str[] = state.split(",");  
  13.         this.mSecurityEntity = str[0];  
  14.         this.mPermit = str[1];  
  15.     }  
  16.   
  17.     @Override  
  18.     public boolean match(String securityEntity, String permit) {  
  19.         if (mSecurityEntity.equals(securityEntity) && mPermit.equals(permit)) {  
  20.             return true;  
  21.         }  
  22.         return false;  
  23.     }  
  24.   
  25. }  
享元工厂:

[java]
  1. public class FlyWeightFactory {  
  2.     private static FlyWeightFactory mFactory = new FlyWeightFactory();  
  3.   
  4.     private FlyWeightFactory() {  
  5.   
  6.     }  
  7.   
  8.     public static FlyWeightFactory getInstance() {  
  9.         return mFactory;  
  10.     }  
  11.   
  12.     /** 
  13.      * 缓存多个人IFlyWeight 对象 
  14.      */  
  15.     private Map<String, IFlyWeight> flyMap = new HashMap<String, IFlyWeight>();  
  16.   
  17.     /** 
  18.      * 获取享元单元 
  19.      * @param key 
  20.      * @return 
  21.      */  
  22.     public IFlyWeight getFlyWeight(String key) {  
  23.         IFlyWeight fly = flyMap.get(key);  
  24.         if(fly==null){  
  25.             fly = new AuthorizationFlyweight(key);  
  26.             flyMap.put(key, fly);  
  27.         }  
  28.         return fly;  
  29.     }  
  30. }  
员工信息的管理工具:

[java]
  1. public class SecurityManager {  
  2.     private static SecurityManager manager = new SecurityManager();  
  3.   
  4.     private SecurityManager() {  
  5.   
  6.     }  
  7.   
  8.     public static SecurityManager getInstance() {  
  9.         return manager;  
  10.     }  
  11.   
  12.     /** 
  13.      * 存放登录人员的权限 
  14.      */  
  15.     private Map<String, Collection<IFlyWeight>> map = new HashMap<String, Collection<IFlyWeight>>();  
  16.   
  17.     public void logon(String user) {  
  18.         Collection<IFlyWeight> coll = queryByUser(user);  
  19.         map.put(user, coll);  
  20.     }  
  21.   
  22.     /** 
  23.      * 从数据库中获取某人所有的权限 
  24.      *  
  25.      * @param user 
  26.      * @return 
  27.      */  
  28.     private Collection<IFlyWeight> queryByUser(String user) {  
  29.         Collection<IFlyWeight> coll = new ArrayList<IFlyWeight>();  
  30.         for (String s : TestDB.coll) {  
  31.             String str[] = s.split(",");  
  32.             if (str[0].equals(user)) {  
  33.                 IFlyWeight fly = FlyWeightFactory.getInstance().getFlyWeight(  
  34.                         str[1] + "," + str[2]);  
  35.                 coll.add(fly);  
  36.             }  
  37.         }  
  38.         return coll;  
  39.     }  
  40.   
  41.     /** 
  42.      * 判断某个用户对某个安全实体是否有某种权限 
  43.      *  
  44.      * @param user 
  45.      *            用户 
  46.      * @param securityEntity 
  47.      *            安全实体 
  48.      * @param permit 
  49.      *            权限 
  50.      * @return 
  51.      */  
  52.     public boolean hasPermit(String user, String securityEntity, String permit) {  
  53.         Collection<IFlyWeight> coll = map.get(user);  
  54.         if (coll == null || coll.size() == 0) {  
  55.             System.out.println(user + "没有登录或者没有该权限...");  
  56.             return false;  
  57.         }  
  58.   
  59.         for (IFlyWeight fly : coll) {  
  60.             if (fly.match(securityEntity, permit)) {  
  61.                 return true;  
  62.             }  
  63.         }  
  64.   
  65.         return false;  
  66.     }  
  67. }  
模拟一个数据库保存员工信息:

[java]
  1. public class TestDB {  
  2.   
  3.     public static Collection<String> coll = new ArrayList<String>();  
  4.   
  5.     static {  
  6.         coll.add("张三,人员列表,查看");  
  7.         coll.add("李四,人员列表,查看");  
  8.         coll.add("李四,薪资列表,查看");  
  9.         coll.add("李四,薪资列表,修改");  
  10.   
  11.         for (short i = 0; i < 3; i++) {  
  12.             coll.add("张三" + i + ",人员列表,查看");  
  13.         }  
  14.     }  
  15. }  

具体的实现,本例子是基于android实现的,java只单独写一个Test类在main里面实现就行了:

  1. SecurityManager manager = SecurityManager.getInstance();  
  2. manager.logon("张三");  
  3. manager.logon("李四");  
  4.                   
  5. boolean b1 = manager.hasPermit("张三", "薪资列表", "查看");  
  6. boolean b2 = manager.hasPermit("李四", "薪资列表", "查看");  
  7. boolean b3 = manager.hasPermit("张三", "人员列表", "查看");  
  8. System.out.println("b1 = "+b1);  
  9. System.out.println("b2 = "+b2);  
  10. System.out.println("b3 = "+b3);  
运行效果:

        

从数据库中可以看出来,张三是人事的普通员工,只能查看公司在职人员,对员工的薪资无权限查看,b1返回false,b3返回true

李四是人事普通员工兼财务主管,可以修改查询员工薪资并且可以查看在职员工信息,b2返回true

如果    

[java]
  1. boolean b4 = manager.hasPermit("王武", "人员列表", "查看");  
因为“王武”这个人没有登录,所以提示信息是  “没有登录或者没有该权限...”

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多