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

Posted 一起来搬砖呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之享元模式(结构型)相关的知识,希望对你有一定的参考价值。

1、享元模式介绍

享元模式(Flyweight),主要用来减少创建对象的数量,以减少内存占用和提高性能。运用共享技术有效的支持持大量细粒度的对象。

  • flyweight 是轻量级的意思,指拳击比赛中的特轻量级拳击手。这个设计模式的作用就是为了将对象变,也就是对象使用的内存大小。一般情况下需要大量对象使用 new 进行创建,会消耗大量内存。
  • 享元模式中可以共享的内容称为内部状态,需要外部环境来设置的不能共享的内容称为外部状态。这两种状态是相互独立的,使用 flyweight 模式将一个对象的状态分为内部状态和外部状态,内部状态保持不变,共享不变的部分以达到减少内存占用的目的
  • 支持大量细粒度对象是因为在实际程序中,能够共享的内部状态比较有限,所以享元对象一般都比较小,包含的内部状态较少,所以称之为细粒度对象

2、享元模式结构


享元模式角色:

  • Flyweight:享元接口,定义具体享元角色需要实现的方法,通过接口传入外部状态

    /**
     * 享元接口
     */
    public interface Flyweight 
    
        /**
         * 可以将外部状态作为参数传入方法,但不能改变方法的内部状态
         */
        void operator(String extrinsicStatus);
    
    
    
  • ConcreteFlyweight:具体享元对象,可共享内部状态,内部状态在创建时赋予,对象创建之后不再更改,外部状态使用参数传入

    /**
     * 具体享元对象
     */
    public class ConcreteFlyweight implements Flyweight 
    
        /**
         * 内部状态
         */
        private String internalStatus = null;
    
        public ConcreteFlyweight(String internalStatus) 
            this.internalStatus = internalStatus;
        
    
        public ConcreteFlyweight() 
        
    
        @Override
        public void operator(String extrinsicStatus) 
            System.out.println("internalStatus = " + this.internalStatus);
            System.out.println("extrinsicStatus = " + extrinsicStatus);
        
    
    
    
  • UnsharedConcreteFlyweight:不需要共享的 Flyweight 子类,并不是所有的享元对象都可以共享,非共享的享元对象通常是享元对象的组合对象

    /**
     * 不共享的享元对象
     */
    public class UnsharedConcreteFlyweight implements Flyweight 
    
        @Override
        public void operator(String extrinsicStatus) 
            System.out.println("不共享的 extrinsicStatus = " + extrinsicStatus);
        
    
    
    
  • FlyweightFactory:享元工厂角色,负责创建和管理享元角色

    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 享元工厂
     */
    public class FlyweightFactory 
    
        private Map<String, Flyweight> maps = new HashMap<>();
    
        /**
         * 单例
         */
        private static FlyweightFactory instance = new FlyweightFactory();
    
        public static FlyweightFactory getInstance() 
            return instance;
        
    
        /**
         * 根据 key 获取享元对象
         */
        public Flyweight getFlyweight(String key) 
            // 先从缓存中获取对象,对象不存在则创建对象放入容器中
            if (!maps.containsKey(key)) 
                maps.put(key, new ConcreteFlyweight());
            
            return maps.get(key);
        
    
    
    
  • 调用方

    public class FlyweightClient 
    
        public static void main(String[] args) 
            FlyweightFactory factory = FlyweightFactory.getInstance();
            Flyweight flyweightA = factory.getFlyweight("A");
            flyweightA.operator("A");
    
            Flyweight flyweightB = factory.getFlyweight("B");
            flyweightB.operator("B");
    
            UnsharedConcreteFlyweight unsharedConcreteFlyweight = new UnsharedConcreteFlyweight();
            unsharedConcreteFlyweight.operator("C");
    		// internalStatus = null
    		// extrinsicStatus = A
    		// internalStatus = null
    		// extrinsicStatus = B
    		// 不共享的 extrinsicStatus = C
        
    
    
    

3、享元模式使用场景

  • 程序使用了大量的对象,这些大量的对象对内存的压力会比较大的时候可以考虑使用
  • 对象的大部分状态是外部状态的话,删除对象的外部状态,可以用相对较少的共享对象取代多组对象的话,可以使用共享模式。

比如下棋游戏,一盘棋局可以下很多棋子,常规思维的话每个棋子都是一个对象,每局都会产生很多对象。使用 flyweight 模式的话,棋子的颜色一般是比较少而且不变的,颜色可以作为内部状态,棋子的区别在于它们的位置不同,棋子的坐标可以作为外部状态,这样的话棋子对象最多可以减少到两个实例。

字符串 String 就运用了 flyweight,创建相同的字符串时,会将后创建的字符串的引用指向先创建的字符串,实现字符串再内存中的共享

4、享元模式优缺点

  1. 享元模式可以有效的支持大量细粒度的对象
  2. 使用享元模式需要维护一个记录了系统已有的所有享元的容器,而且为了使对象共享,将一些状态外部化,程序的逻辑可能会变得复杂。最好在足够多的对象实例可供共享的时候才使用享元模式

以上是关于设计模式之享元模式(结构型)的主要内容,如果未能解决你的问题,请参考以下文章

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

15结构型模式之享元模式

结构型模式之享元模式

结构型模式之享元

《精通Python设计模式》学习结构型之享元模式

揭秘设计模式之享元模式