【设计模式】享元模式

享元模式理解

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

 

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

 

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

  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=男

 

posted @ 2021-08-23 22:43  夏夜凉凉  阅读(13)  评论(0编辑  收藏  举报