结构型设计模式之享元模式(Flyweight)

设计模式之享元模式

享元模式应该怎么来实现?什么情况下会用到享元模式?有什么好处?

先来设计一个场景,读过大学的都知道,到了期末的时候,大家就要开始准备选择自己下学期的课程,以及老师。在这个时候由于选课的集中,以及访问选课页面的增多,从而会导致生成的对象增多,此时的内存占用率肯定会暴增,如果学校的服务器内存不够,那么很可能会出现OOM的情况。
下面简单模拟一下创建课程对象:

public class FlyWeight_01 {

    //课程类
    static class Course{
        private Integer id;//课程ID
        private String courseName;//课程名称
        private String teacher;//授课老师
        private String address;//授课地址

        public Course(Integer id, String courseName, String teacher, String address) {
            this.id = id;
            this.courseName = courseName;
            this.teacher = teacher;
            this.address = address;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getCourseName() {
            return courseName;
        }

        public void setCourseName(String courseName) {
            this.courseName = courseName;
        }

        public String getTeacher() {
            return teacher;
        }

        public void setTeacher(String teacher) {
            this.teacher = teacher;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }
    }

    public static void main(String[] args) {
        //物理课-张老师
        Course physicsCourse1 = new Course(1,"物理课","张老师", "A-1");
        //物理课-李老师
        Course physicsCourse2 = new Course(1,"物理课","李老师", "A-2");
        //高数课-赵老师
        Course mathCourse1 = new Course(2,"高数课","赵老师", "B-1");
        //高数课-蒙老师
        Course mathCourse2 = new Course(2,"高数课","蒙老师", "B-2");
    }
}

同一门课程,对应了不同的老师,以及不同的教师,如果采用以上创建对象的方式来频繁创建选课列表,那么就会导致对象重复创建和对象的数量的激增,从而使得内存占用率迅速上升以至于出现OOM。

按理来讲,这么简单的一个创建对象的功能是不应该导致OOM,但是偏偏就出现了,既然出现了的话,那么就应该想办法来解决。
而解决的办法就是对象的重复利用,所谓的重复利用就是同一个课程、同一个老师、同一个上课地址的对象,我们只需要创建一次即可,如果其他同学也要选择改老师的课程,只需要将该对象提供即可,不必再重新创建。

那到底应该怎么来做呢:

  1. 首先要做的就是将课程中相同的属性全部抽离出来,单独形成一个类或抽象类(这部分属性值在初次设值之后就不应该再发生改变);
  2. 其次必须要定义一个指向该类实例的唯一标志;
  3. 最后需要有一个容器来保存已经创建过的对象,同时还必须有一个唯一标志指向该对象(因为必须保证通过该标志取到的对象始终都是同一个)
    如下代码:
public class FlyWeight_02 {

    //抽象课程类
    static abstract class AbstractCourse{
        private Integer id;//课程ID
        private String courseName;//课程名称
        private String teacher;//授课老师
        private String address;//授课地址

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getCourseName() {
            return courseName;
        }

        public void setCourseName(String courseName) {
            this.courseName = courseName;
        }

        public String getTeacher() {
            return teacher;
        }

        public void setTeacher(String teacher) {
            this.teacher = teacher;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }
    }

    //具体课程类
    static class ConcreteCourse extends AbstractCourse{
        private final String key;//用final修饰,保证key不会被改变
        public ConcreteCourse(String key) {
            this.key = key;
        }
    }

    //工厂方法模式创建课程
    static class CourseFactory{
        private static Map<String, AbstractCourse> courseMap = new HashMap<>();

        public static AbstractCourse createCourse(String key){
            if(!courseMap.containsKey(key)){
                AbstractCourse course = new ConcreteCourse(key);
                //初始化,设置参数
                String[] arr = key.split("_");
                course.setId(Integer.valueOf(arr[0]));
                course.setCourseName(arr[1]);
                course.setTeacher(arr[2]);
                course.setAddress(arr[3]);
                courseMap.put(key, course);
            }
            return courseMap.get(key);
        }
    }

    public static void main(String[] args) {
        AbstractCourse course = CourseFactory.createCourse("1_物理课_张老师_A-1");
        AbstractCourse course1 = CourseFactory.createCourse("1_物理课_李老师_A-2");
        AbstractCourse course2 = CourseFactory.createCourse("2_高数课_赵老师_B-1");
        AbstractCourse course3 = CourseFactory.createCourse("2_高数课_蒙老师_B-2");
        //再次获取张老师的物理课,对比是否是同一个对象
        AbstractCourse course01 = CourseFactory.createCourse("1_物理课_张老师_A-1");
        System.out.println(course01==course);
        System.out.println(course01.equals(course));
    }
}

打印结果:

true
true

由此可以说明,第一次创建的对象得到了重复利用,这也就是享元模式。

下面来看看享元模式的定义:使用共享对象可有效的支持大量的细粒度的对象。

细粒度对象,就是将对象分为两部分,一部分是外部状态,一部分是内部状态;
内部状态,是不随环境变化而变化的,也就是固定的;
外部状态,随环境变化而变化的,如创建时传入的key。

享元模式主要应用池化技术,如:线程池,避免线程的重复创建带来的性能消耗,且可以统一管理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值