java 设计模式之享元模式(十一)

127 阅读4分钟

java 设计模式之享元模式①①

人生是需要奋斗的,只有你奋斗了,失败后才会问心无愧;人生是单行路,只有奋斗了,才会有光明的前途;人生中有许多的竞争对手,正因有这么多的竞争对手,所以我们更得奋斗!

设计模式学习,近期我会把23种设计模式都写成博客,敬请期待~
—2021/1/12

定义

又称之为蝇量模式;运用共享技术有效的支持大量细粒度的对象。

百度百科

使用场景

如果一个应用程序使用了大量的对象,而这些对象造成了很大的存储开销的时候就可以考虑是否可以使用享元模式。

例如,如果发现某个对象的生成了大量细粒度的实例,并且这些实例除了几个参数外基本是相同的,如果把那些共享参数移到类外面,在方法调用时将他们传递进来,就可以通过共享大幅度单个实例的数目。

问题分析

假设我现在要创建一个正方形,一个长方形,一个圆形,一个三角形,

通常的思维应该是:使用工厂模式,因为他们的相似度都很高,都属于一系列的’产品’,但是呢他们会创建多个实例,造成内存浪费

解决思路:
把他们整合到一起,共享相关的代码和数据,和单例模式有几分类似,这里就用到列享元模式

享元模式和单例模式的区别

  • 单例模式是整个系统共用一个实例
  • 享元模式是整个系统共用好几个同类型对象而且享元模式的共享对象是按照需要来分配,如果不存在会自动创建
  • 单例模式不会创建第二个实例
  • 享元模式里的共享对象一定是线程私有的,比如说共享单车,虽然是共享的,但是使用的是他就是你的,不过是有借有还,在某种程度上是共享的

外部状态和内部状态

  • 内部状态是可以共享的,存储在享元内部,不会随环境的改变而有所不同.
  • 外部状态是不可以共享的,它随环境的改变而改变的,因此外部状态是由客户端来保持(因为环境的变化是由客户端引起的).

这里看不懂没关系,看完代码就懂了!

UML类图(2.1):
在这里插入图片描述

角色分析

  • 抽象享元角色(Flyweight) :为具体享元角色规定了必须实现的方法,而外部状态就是以参数的形式通过此方法传入。在Java中可以由抽象类、接口来担当。
  • 具体享元角色(ConcreteFlyweight) :实现抽象角色规定的方法。如果存在内部状态,就负责为内部状态提供存储空间。
  • 享元工厂角色(FlyweightFactory) :负责创建和管理享元角色。要想达到共享的目的,这个角色的实现是关键!
  • 客户端角色(Client) :维护对所有享元对象的引用,而且还需要存储对应的外蕴状态

这里看不懂没关系,看完代码就懂了!

内部状态代码实现

IShape(抽象享元角色):

public interface IShape {
    public void showShape();
}

ShapeImpl(具体享元角色):

public class ShapeImpl  implements IShape{

    //内部享元部分 (形状)
    private String type = "";

    public ShapeImpl(String type) {
        this.type = type;
    }

    @Override//外部享元角色
    public void showShape() {
        Log.i("享元模式","绘制 "+type+" 成功 ");
    }
}

这里的type就是内部状态,是可以共享的.不会随环境的改变而有所不同.

ShapeFactory (享元工厂角色)

public class ShapeFactory {

    HashMap<String,ShapeImpl> hashMap = new HashMap<>();
	//设置type
    public IShape getShape(String type){
        if (!hashMap.containsKey(type)) {
                hashMap.put(type,new ShapeImpl(type));
       }
        return hashMap.get(type);
    }

	//获取hashMap数量
    public int getShapeSize(){
        return hashMap.size();
    }
}

这里为什么要使用HashMap?

HashMap特征:

  • HashMap的底层主要是基于数组和链表实现的,
  • 之所以有相当快的查询速度主要是因为它是通过计算散列码来决定存储位置的。
  • HashMap是可以序列化的。是线程不安全的。
  • HashMap可以保证key唯一

因为HashMap可以保证key唯一,咋们传入一个key如果存在返回对应的对象,如果没有创建该对象,达到’单例’的效果

又因为HashMap线程不安全,所以享元模式不建议在多线程情况下使用.

测试方法:

ShapeFactory shapeFactory = new ShapeFactory();
IShape shape1 = shapeFactory.getShape("正方形");
IShape shape2 = shapeFactory.getShape("正方形");
IShape shape3 = shapeFactory.getShape("三角形");
IShape shape4 = shapeFactory.getShape("正方形");
shape1.showShape();
shape2.showShape();
shape3.showShape();
shape4.showShape();

Log.i("享元模式","总个数为: "+shapeFactory.getShapeSize()+"");

Log图(1.1):
在这里插入图片描述
可以看到,虽然存放了3个正方形,可是打印出来的总个数还是2个,因为内部只有2种类型(正方形和三角形)

但是可以看出,代码中只有对内部状态使用的,没有外部状态,接下来添加外部状态

外部状态代码实现

IShape(抽象享元角色):

public interface IShape {
    //由客户端输入外部状态 
    public void showShape(Color color);
}

这里的Color color就是外部状态,外部状态不可以共享,外部状态由客户输入,它随环境的改变而改变的.

Color(外部状态):

public class Color {
    private String color = "";
    public Color(String color) {
        this.color = color;
    }
    public String getColor() {
        return color;
    }
}

ShapeImpl(具体享元角色):

public class ShapeImpl  implements IShape{

    //共享部分 (形状)
    private String type = "";

    public ShapeImpl(String type) {
        this.type = type;
    }

    @Override//外部享元角色
    public void showShape(Color color) {
        Log.i("享元模式","绘制 "+type+" 成功 颜色为:"+color.getColor());
    }
}

这里的type就是内部状态,是可以共享的.不会随环境的改变而有所不同.

ShapeFactory (享元工厂角色)

public class ShapeFactory {

    HashMap<String,ShapeImpl> hashMap = new HashMap<>();

    public IShape getShape(String type){
        if (!hashMap.containsKey(type)) {
                hashMap.put(type,new ShapeImpl(type));
       }
        return hashMap.get(type);
    }
    public int getShapeSize(){
        return hashMap.size();
    }
}

测试方法:

ShapeFactory shapeFactory = new ShapeFactory();

IShape shape1 = shapeFactory.getShape("正方形");
IShape shape2 = shapeFactory.getShape("正方形");
IShape shape3 = shapeFactory.getShape("三角形");
IShape shape4 = shapeFactory.getShape("正方形");

shape1.showShape(new Color("红色"));
shape2.showShape(new Color("红色"));
shape3.showShape(new Color("黄色"));
shape4.showShape(new Color("黑色"));

Log.i("享元模式","总个数为: "+shapeFactory.getShapeSize()+"");

Log图(1.2):
在这里插入图片描述
外部状态就是对外开放,由用户定义,不可以共享
内部状态就是可以共享,如果有相同的值则不重新创建,就使用共享的.

完整代码

去设计模式/设计原则主页

原创不易,您的点赞就是对我最大的支持,留下您的点赞吧~