• 【设计模式】享元模式


    享元模式理解

    世上没有两片相同的叶子,尽管他们可能在颜色、大小或者重量上相同,但是纹路可能不同 如果要让我们来描述这两片叶子,一种方法是分别描述,另外一种方法就是先描述他们的共同点,再分别描述他们各自的特点。那么很明显第二种方法节省了时间,提高了效率。

     

    那么享元模式大概就是这个意思,抽取相同的属性放入一个容器以便共享,并且可以保证该属性不会随外部环境变化而变化。

     

    说的可能不好理解,用大白话举个例子

    1. 创建一个用户user类,里面有属性:体重weight、年龄age、性别sex,还有一个获取用户信息的方法getUserMsg。

    2. 创建一个HashMap,里面的key存年龄,value存user对象。这个user对象里除了年龄属性是有的,其他属性都为空,且年龄属性值就等于key的值。

    3. 创建多个user对象,每次创建的时候需要指定年龄并通过年龄先去判断map中是否有相同年龄的对象,如果有,就拿出来用,如果没有就新建。

       

    通过上面的例子可以看出,这种模式,特别适合 系统中有大量相似对象且这些对象消耗了大量的内存的时候,以此来减少对象的创建,降低系统的内存。

     

    在jvm中,有串池的概念,就是创建一个String类型的字符串的时候,如果串池中有一样的字符串,就不会创建,如果没有才会创建并放在串池中。

    在数据库中,数据库连接池的概念,也是一个效果。

     

    这里还要提两个概念:

      内部状态 :不会随着环境的改变而改变

      外部状态 :随着环境的改变而改变

    代码案例

    实现享元模式,共分四步:

    1. 创建一个抽象用户接口,里面有一个获取信息的抽象方法

      目的是可以通过此方法来实现某些特定的业务

    2. 创建一个用户类实现抽象用户接口,定义三个属性,其中体重和性别都是固定的,年龄是可以变化的。并接着定义一个参数为age的有参构造方法,重写接口中的方法。

    3. 创建一个创建用户的工厂类,定义一个以age为key,user对象为value的hashmap,并提供一个获取用户的方法,方法里定义逻辑为,如果没有此年龄的对象就新建一个并放入map中,如果有就直接从map中获取。

    4. 创建一个测试类,使用工厂类中的创建用户的方法创建四个用户,其中两个为重复的。

    5. 最后可以看到结果是,共创建了三个对象,而不是四个,第四个对象创建的时候发现map中有相同age的,所以直接就从map获取了。

    6. 最后要提一点,为了防止创建对象之后修改了对象的除age之外的其他属性的值,这里使用了final关键字做了处理。

    案例描述:

      要求为创建四个体重为60kg,性别为男的用户。

    public interface AbstractUser {
      //可以通过这里的抽象方法,目的是为了实现某些特定的业务,这里将功能定义成获取用户的信息
        void getUserMsg();
    }
    @Data
    public class User implements AbstractUser {
    
        //内部状态 不会随着环境的改变而改变
        private final String weight="60kg";
        private final String sex="男";
        //外部状态 随着环境的改变而改变的
        private Integer age;
        //参数为age的构造方法
        public User(Integer age) {
            this.age = age;
        }
        //特定业务逻辑的具体实现
        @Override
        public void getUserMsg() {
            System.out.println("用户信息为:weight=" + weight + "  age=" + age + "  sex=" + sex);
        }
    }
    public class UserFactory {
        //定义一个HashMap用来存储所有的共享对象
        private static final HashMap<Integer, User> userMap = new HashMap<>();
        //工厂类获取用户的方法
        public static User getUser(Integer age){
            //先判断map里是否有
            User user = (User) userMap.get(age);
            if(user == null){
                //map里没有就新创建一个
                user = new User(age);
                userMap.put(age, user);
                System.out.println("新创建了一个用户:"+user);
            }else{
                System.out.println("使用已创建的用户:"+user);
            }
            return user;
        }
    }
    public class Test {
        public static void main(String[] args) {
            //根据年龄创建四个对象
              //可以看到在创建最后一个的时候因为在map中有相同年龄的对象,所以没有新建
            User user1 = UserFactory.getUser(21);
            User user2 = UserFactory.getUser(22);
            User user3 = UserFactory.getUser(23);
            User user4 = UserFactory.getUser(21);
            user1.getUserMsg();
            user2.getUserMsg();
            user3.getUserMsg();
            user4.getUserMsg();
        }
    }
    //效果
    新创建了一个用户:User(weight=60kg, sex=男, age=21)
    新创建了一个用户:User(weight=60kg, sex=男, age=22)
    新创建了一个用户:User(weight=60kg, sex=男, age=23)
    使用已创建的用户:User(weight=60kg, sex=男, age=21)
    用户信息为:weight=60kg  age=21  sex=男
    用户信息为:weight=60kg  age=22  sex=男
    用户信息为:weight=60kg  age=23  sex=男
    用户信息为:weight=60kg  age=21  sex=男
  • 相关阅读:
    Struts之上传
    Struts之准备工作
    前端--关于背景、浮动和定位
    javascript学习目录
    audio和video元素
    js实现动态操作table
    jquery全选、反选、全不选
    js实现页面跳转
    10 个非常有用的 AngularJS 框架
    JavaScript 语言基础知识点总结(思维导图)
  • 原文地址:https://www.cnblogs.com/flyinghome/p/15178075.html
Copyright © 2020-2023  润新知