美文网首页Java随笔-生活工作点滴
设计模式之享元模式(十八)

设计模式之享元模式(十八)

作者: 3d0829501918 | 来源:发表于2019-07-09 19:00 被阅读11次

      以前想骑自行车需要去自行车店里购买,才能骑自行车。现在有了共享单车,我们则不需要购买单车,只需要扫描二维码就可以来一场说走就走的短途。共享单车的这种模式,我们可以理解为享元模式。

    一、享元模式的定义

      所谓享元模式就是运行共享技术有效地支持大量细粒度(对象的相似度比较高的属性)对象的复用。系统使用少量对象,而且这些对象都比较相似,状态变化小,可以实现对象的多次复用。


    二、享元模式类图


    三、享元模式的角色

    • Flyweight
      抽象享元类。所有具体享元类的超类或者接口。Flyweight可以接受并作用于外部状态。

    • ConcreteFlyweight
      具体享元类。指定内部状态,为内部状态增加存储空间。

    • UnsharedConcreteFlyweight
      非共享具体享元类。指出那些不需要共享的Flyweight子类。

    • FlyweightFactory
      享元工厂类。用来创建并管理Flyweight对象,它主要用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory就会提供一个已经创建的Flyweight对象或者新建一个(如果不存在)。


    四、情景代码

    小明、小王、小李三个人要骑自行车,接下来我们用代码来实现。

    • 自行车类
    public class Bicycle {
    
    private  String name;
    
    public Bicycle (String name) {
        this.name = name;
    }
    
    public void  rideBicycle () {
        System.out.println(name+" 骑自行车");
    }
    
    }
    
    • 测试类
    public static void main(String[] args) {
        Bicycle bicycle1 = new Bicycle("小明");
        bicycle1.rideBicycle();
    
        Bicycle bicycle2 = new Bicycle("小王");
        bicycle2.rideBicycle();
    
        Bicycle bicycle3 = new Bicycle("小李");
        bicycle3.rideBicycle();
    }
    

      通过上面的例子,我们可以看出,谁要骑车都需要创建一个对象,对象都是相同的,这样对内存消耗是比较大的,而且也不符合设计模式编程。接下来我们用享元模式来实现。

    • 定义一个车类的接口
    public interface Car {
           public void  rideCar (String userName);
    }
    
    • 非享元的实现类
    public class CarNoImpl implements Car {
    
    @Override
    public void rideCar(String userName) {
        System.out.println(userName+"骑单车");
    }
    }
    
    • 享元工厂类
    public class CarFactory {
          //  享元池
          //  如果找到了,不需要创建新的对象。包含了两个意思,第一个意思:减少了对象的创建,第二个,提高了对象的重复利用。
          private static Map<String,Object> filweighs = new HashMap<String,Object>();
    
          public Car getCar(String key,Car car) {
                 if (!filweighs.containsKey(key)) {
                      filweighs.put(key, car);
                 }
              return (Car) filweighs.get(key);
          }
    }
    
    • 测试类
    public static void main(String[] args) {
    
       CarFactory carFactory = new CarFactory();
       Car car1 = carFactory.getCar("红色",new CarNoImpl());
       car1.rideCar("小明");
    
       Car car2 = carFactory.getCar("蓝色",new CarNoImpl());
       car2.rideCar("小王");
    
       Car car3 = carFactory.getCar("红色",new CarNoImpl());
       car3.rideCar("小李");
    }
    
    • 测试结果
     小明骑自行车
     小王骑自行车
     小李骑自行车
    
    

      小明、小李骑的是红色的单车,这时我们的享元工厂是通过颜色查找,如果集合中有这个对象,则不需要创建直接返回集合中的对象,如果没有则需要创建对象,下次直接获取享元池中的对象,这样避免频繁创建对象。

    接下来我们来聊聊共享部分,也就是外部状态。

    • 享元实现类
    public class CarOkImpl implements Car {
    
    public Car car;
    
    public CarOkImpl(Car car) {
        this.car = car;
    }
    
    @Override
    public void rideCar(String userName) {
        if (null == car) {
            System.out.println("附近没有单车可骑");
            return;
        }
        car.rideCar(userName);
    }
    }
    
    • 测试类
    public static void main(String[] args) {
    
       Car car4 = carFactory.getCar("黑色",new CarOkImpl(null));
       car4.rideCar("小王");
    
    }
    
    • 测试结果
     附近没有单车可骑
    

      测试我们发现非享元实现类是不会改变内部类的状态,享元实现类是通过客户端可以改变内部类的状态。
      这就是享元的模式的两种状态,内部状态和外部状态。
      内部状态存储于享元对象内部,而外部状态则应该由客户端来考虑。


    五、享元模式的优缺点

    • 优点

      1、享元模式的优点在于它能够极大的减少系统中对象的个数。
      2、享元模式由于使用了外部状态,外部状态相对独立,不会影响到内部状态,所以享元模式使得享元对象能够在不同的环境被共享。

    • 缺点

      1、由于享元模式需要区分外部状态和内部状态,使得应用程序在某种程度上来说更加复杂化了。
      2、为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。


    六、适用场景

      如果一个系统中存在大量的相同或者相似的对象,由于这类对象的大量使用,会造成系统内存的耗费,可以使用享元模式来减少系统中对象的数量。
      对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。


    七、小结

      享元模式可以极大地减少系统中对象的数量。但是它可能会引起系统的逻辑更加复杂化。享元模式的核心在于享元工厂,它主要用来确保合理地共享对象。
      内部状态为不变共享部分,存储于享元对象内部,而外部状态是可变部分,它应当客户端来负责。


    源码在这里GitHub:
    https://github.com/xiaonongOne/flyweight

    注意啦! 往期设计模式在这里

    相关文章

      网友评论

        本文标题:设计模式之享元模式(十八)

        本文链接:https://www.haomeiwen.com/subject/stxfkctx.html