Java设计模式——享元模式(蝇量模式)

Java设计模式之蝇量模式(享元模式)

蝇量可以理解为很小的数量,享元可以理解为共享的元素;通过这两个理解,我们初步可以知道该模式就是把对象的数量减少,让他们之间可以共享使用

享元模式:让一个类的实例可以提供多个“虚拟实例”,创建较少的对象实例,多与工厂模式一起使用。

  • 内部状态:不会变化的状态,可以共享的状态
  • 外部状态:会随着对象不同二有不同的状态,不可以共享的状态

角色:

  • Flyweight(抽象享元类):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法
  • ConcreteFlyweight(具体享元类):它实现了抽象享元类,其实例称为享元对象
  • UnsharedConcreteFlyweight(非共享具体享元类):不能被共享的子类可设计为非共享具体享元类
  • FlyweightFactory(享元工厂类):享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中,如果存在需要的对象就从池中拿(Map),不存在就创建

使用

场景:在网络围棋比赛中,一个棋盘有361个棋子,我们不需要创建361个棋子对象,我们使用享元模式实现

  • 颜色是内部状态可以共享,位置时外部状态不可以共享,将作为参数传入,我们就可以只需要2个实例(一黑一白),在需要棋子的时候从棋子工厂中拿相应颜色的棋子,外部变量位置调用下棋方法时传入

代码:

  • Color 枚举颜色类
public enum  Color {
    WHITE,BLACK
}
  • FlyWeight 棋子方法接口
public interface FlyWeight {
    public void display(int x,int y);
    public Color getColor();
    public void setColor(Color color);
}
  • ChessFlyWeight 棋子实现类
public class ChessFlyWeight implements FlyWeight{
    private Color color;//内部状态
    public void setColor(Color color) {
        this.color = color;
    }
    public Color getColor() {
        return color;
    }
    //外部状态作为参数传入
    public void display(int x, int y) {
        System.out.println("you put a "+getColor().name().toLowerCase()+" chess at "+"("+x+","+y+")");
    }
}
  • ChessFlyweightFactory 棋子工厂类
public class ChessFlyweightFactory {
    //定义一个HashMap用于存储享元对象,实现享元池
    private HashMap<Color,FlyWeight> flyweights = new HashMap<>();
    public FlyWeight getFlyweight(Color color){
        //如果对象存在,则直接从享元池获取
        if(flyweights.containsKey(color)){
            return flyweights.get(color);
        }
        //如果对象不存在,先创建一个新的对象添加到享元池中,然后返回
        else {
            FlyWeight fw = new ChessFlyWeight();
            fw.setColor(color);
            flyweights.put(fw.getColor(),fw);
            return fw;
        }
    }
}
  • 测试
public class ChessGameTest {
    public static void main(String[] args) {
        Random random = new Random();
        ChessFlyweightFactory flyweightFactory = new ChessFlyweightFactory();
        ChessFlyWeight chess1 = (ChessFlyWeight) flyweightFactory.getFlyweight(Color.BLACK);
        chess1.display(random.nextInt(361),random.nextInt(361));

        ChessFlyWeight chess2 = (ChessFlyWeight) flyweightFactory.getFlyweight(Color.WHITE);
        chess2.display(random.nextInt(361),random.nextInt(361));
    }
}

输出:
you put a black chess at (243,252)
you put a white chess at (261,147)

Java中享元模式使用

String类

Java中String类被修饰为final类,保证了安全性,不能被继承,值创建出来不能被修改,是可以共享的。

当使用:

String s = "abd";这种字面量的形式创建String时,它是会加载到常量池,而不是创建的对象放在堆,常量的拼接还是常量,池中对应的字面量字符串都只会保存一个

但是使用:

String s = "abd";这种方式创建的String会放在堆里而不是常量池中。

String s = "kobe";
String s1 = "ko";
String s2 = "be";
String s3 = s1+s2;
String s4 = new String("kobe")
String s5 = s4.intern();

s == s3? true
s == s4? false
s == s5? true
  • intern方法

存在于.class文件中的常量池,在运行期被JVM装载,并且可以扩充。String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用;

池技术

  • 对象池、线程池、数据连接池、常量池都是池技术的使用

池技术:其实就是在一个集合,里面包含了我们需要的对象集合,当然这些对象都被池化了,也就是被对象池所管理,想要这样的对象,从池子里取个就行,但是用完得归还,每个需要的元素是有限个。

  • 常量池只保存一个相同字符串引用
  • 数据连接池、线程池可包含多个实例,用完需放回

优点:

  • 主要用于减少创建对象的数量,以减少内存占用和提高性能。

缺点:

  • 提高了系统的复杂度,需要分离出外部状态和内部状态

代码地址:Github享元模式


Java设计模式|策略模式

Java设计模式|观察者模式

Java设计模式|装饰者模式

Java设计模式|工厂模式

Java设计模式|命令模式

Java设计模式|适配器模式和外观模式

Java设计模式|模板方法模式

Java设计模式|迭代器模式和组合模式

Java设计模式|状态模式

Java设计模式|代理模式

Java设计模式|单例模式

Java设计模式|备忘录模式

Java设计模式|访问者模式

Java设计模式|复合模式

Java设计模式|桥接模式

Java设计模式|生成器模式

Java设计模式|享元模式/蝇量模式

Java设计模式|原型模式

Java设计模式|责任链模式

Java设计模式|中介者模式

  • 本文作者: dzou | 微信:17856530567
  • 本文链接: http://www.dzou.top/post/12fa71d.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
  • 并保留本声明和上方二维码。感谢您的阅读和支持!