设计模式-享元模式

107 阅读3分钟

​​本文已参与「新人创作礼」活动,一起开启掘金创作之路。

模式意图

在实现某一功能时,要获取若干相似对象,但不同对象会占用太多内存,将获取的对象复用,减少内存消耗。

模式结构

  • 享元工厂:负责创建和管理享元角色,当需要具体享元对象时,先获取享元工厂,再检查享元工厂中是否存在该对象,若存在再从享元工厂中去获取对象。
  • 抽象享元角色:定义享元类的公共方法
  • 具体享元角色:每一个享元类提供一个唯一的对象存储在享元工厂中
  • 非享元角色:不存在享元工厂中的类,但可以继承抽象享元角色,需要时直接创建

俄罗斯方块案例

每种形状的图形都可以看作一个类,由于这些图形是重复出现的,如果每次生成一个图形都创建一个对象,会非常浪费空间,可以考虑用享元模式。

​编辑

享元工厂:BoxFacory

抽象享元类:AbstractBox

具体享元类:IBox,LBox,OBox

​编辑

 抽象享元类的功能是定义规范和提高代码复用,子类具体享元类是有相似特点的类,

享元工厂类将具体享元类装到集合中,提供向外获取具体享元类的方法。

package mode;

import javax.swing.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class Client{
    public static void main(String[] args) {
        AbstractBox box1 = BoxFactory.getInstance().getShape("I");
        box1.display("蓝色");
        AbstractBox box2 = BoxFactory.getInstance().getShape("L");
        box2.display("绿色");
        AbstractBox box3 = BoxFactory.getInstance().getShape("I");
        System.out.println(box1==box3);//true
    }
}
//抽象享元角色
abstract class AbstractBox{
    //获取图形,定义规范
    public abstract String getShape();
    //显示图形及颜色,提高代码复用
    public void display(String color){
        System.out.println("方块形状:"+getShape()+", 颜色"+color);
    }
}
//享元工厂类,将该类设计成单例
class BoxFactory{
    private HashMap<String,AbstractBox> map;
    private static BoxFactory boxFactory = new BoxFactory();
    private BoxFactory(){
        map = new HashMap<>();
        map.put("I",new IBox());
        map.put("L",new IBox());
        map.put("O",new IBox());
    }
    //根据名称获取图形对象
    public AbstractBox getShape(String name){
        return map.get(name);
    }

    public static BoxFactory getInstance(){
        return boxFactory;
    }


}
//具体享元
class IBox extends AbstractBox{
    @Override
    public String getShape() {
        return "I";
    }
}

class LBox extends AbstractBox{
    @Override
    public String getShape() {
        return "L";
    }
}

class OBox extends AbstractBox{
    @Override
    public String getShape() {
        return "O";
    }
}

优点

  • 减少内存中相似或相同对象的数量,节约系统资源,提高系统性能
  • 享元模式中的外部状态相对独立,不影响内部状态,内部状态就是具体享元对象的属性,内部状态转为外部状态就是将属性转为方法的参数,因为只有一个享元对象,相似的享元对象之间之间是有差异的,所以不能写在属性中,要靠传入形参来使用,比如下例中的颜色参数。

缺点

为了将对象可以共享,需要将享元对象的部分状态(属性)外部化,分离内部状态和外部状态(转化为形参),使程序逻辑复杂。

使用场景

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

JDK源码解析

public static void main(String[] args) {
        Integer i1 = 127;
        Integer i2 = 127;
        System.out.println(i1 == i2);//true
        Integer i3 = 128;
        Integer i4 = 128;
        System.out.println(i3 == i4);//false
    }

Integer类默认先创建并缓存-128到127之间的Integer对象,当赋值的数在-128到127之间时,直接从缓存中返回,否则创建一个新的Integer对象