设计模式 | 享元模式

知识点十三:享元模式


一、概述

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。它属于23种GOF设计模式的结构型设计模式 ,它提供了减少对象数量从而改善应用所需的对象结构的方式。

在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(Flyweight Pool)(用于存储具有相同内部状态的享元对象),将对象放在享元池中重用现有的同类对象,如果未找到匹配的对象,则创建新对象。


二、优缺点及使用场景

1、优点

  • 它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。
  • 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。

2、缺点

  • 享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
  • 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。

3、使用场景

  • 一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费。
  • 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中(细粒度对象)。
  • 使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。

三、模式中的角色及职责和实现方式

1、角色

  • 抽象享元(Flyweight)角色:所有具体享元类的父类,规定一些需要实现的公共接口。
  • 具体享元(ConcreteFlyweight)角色:具体的享元实现对象,必须是可共享的,需要封装享元对象的内部状态。
  • 享元工厂(FlyweightFactory)角色:享元工厂,主要用来创建并管理共享的享元对象,并对外提供访问共享享元的接口。

2、实现方式

享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。

享元模式


四、Java中的实现方式

Person.java

/**
 * @Description: 抽象享元(Flyweight)角色 人
 * @Author: Ling.D.S
 * @Date: Created in 2018/11/22 14:58
 */
public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Staff.java

/**
 * @Description: 具体享元(ConcreteFlyweight)角色 员工
 * @Author: Ling.D.S
 * @Date: Created in 2018/11/22 15:01
 */
public class Staff extends Person {
    private String number; //员工号

    public Staff() {
        super();
    }

    public Staff(String name, int age) {
        super(name, age);
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }
}

StaffFactory.java

/**
 * @Description: 享元工厂(FlyweightFactory)角色
 * @Author: Ling.D.S
 * @Date: Created in 2018/11/22 15:05
 */
public class StaffFactory {
    //我们希望通过员工号来找到员工
    private Map<String,Staff> pool;//资源池

    public StaffFactory() {
        pool = new HashMap<String, Staff>();
    }

    public Staff getStaff(String number){
        Staff staff = pool.get(number);
        //如果staff为null则new一个空的
        if(staff == null){
            System.out.println("没有该员工,添加该员工");
            staff = new Staff();
            staff.setNumber(number);
            pool.put(number,staff);
        }
        return staff;
    }
}

MainClass.java

/**
 * @Description: 有抽象享元角色的实现,客户端调用
 * @Author: Ling.D.S
 * @Date: Created in 2018/11/22 14:58
 */
public class MainClass {
    public static void main(String[] args) {
        //1.创建工厂
        StaffFactory factory = new StaffFactory();
        //2.从工厂取值
        Staff staff1 = factory.getStaff("001");
        Staff staff2 = factory.getStaff("002");
        Staff staff3 = factory.getStaff("003");

        System.out.println(staff1.getNumber());
        System.out.println(staff2.getNumber());
        System.out.println(staff3.getNumber());

        System.out.println("==============");
        //这时候资源池中就有员工123了,现在把"002"改为"001"看是不是同一个对象
        staff2 = factory.getStaff("001");
        if(staff1 == staff2){
            System.out.println("是同一个对象");
        }else{
            System.out.println("不是同一个对象");
        }
    }
}

转载请注明原地址,宋德凌的博客:http://CoderOfSong.github.io 谢谢!

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦