享元模式
1.什么是享元模式
享元模式就像是一个池,可以把系统中需要用到的类给存入里面 但需要使用的时候就可以直接往里面拿,这样就可以节省内存和效率
并且同一种类型的对象可以不止存一个 因为他是分为内部状态和外部状态 外部状态相当于map的key 内部状态相当于value,这就代表着外部状态不能相同但内部状态可以,内部状态可以说同一种类型的类但key必须不同,用key来代表一个类在不同的使用场景的使用。
2.享元模式是做什么的
1、享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
2、在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
3.享元模式的应用场景
1、系统中有大量对象。
2、这些对象消耗大量内存。
3、这些对象的状态大部分可以外部化。
4、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。
5、系统不依赖于这些对象身份,这些对象是不可分辨的。
简单来说就是:1、系统有大量相似对象。 2、需要缓冲池的场景。
4.使用享元模式的好处
1.降低内存占用 : 减少在内存中创建对象的数量 , 节省了内存 , 提高了效率 ;
2.减少创建对象开销 : 创建对象时需要占用一定的开销 , 如 new 操作 ; 可能构造函数中有访问 文件 , 数据库 , 网络 等操作 , 也可以避免这些开销 ;
名词解释
细粒度对象 : 是内存中的数量庞大的对象 ; 实际使用的数量庞大的对象 ;
共享对象 : 多个细粒度对象共享的部分数据 ; 对象缓存池中存储的对象 ;
概念引入 : 区分内部状态和外部状态的目的是为了维护享元模式的对象池 , 当用户想要使用某个对象时 , 如何确定对象池中的对象是否是用户想要调用的对象呢 , 这里就需要一些数据进行对比 , 数据一致 , 就说明是用户想要的对象 , 数据不一致 , 就需要创建新对象 , 放入对象池 ;
1. 内部状态 : 对象的内部状态不能作为对象对比的依据 , 所有对象的内部状态都是一样的数据
2. 外部状态 : 对象的外部状态每个都不一样 , 每个对象都有一个唯一 外部状态 值 , 类似于 身份证 , 哈希码 这一类的信息 ;
3. 身份标识 : 在线程池中 , 使用外部状态信息 , 唯一确定一个对象 , 作为对象的标识信息 ;
代码
父类接口的作用:在集合中只需要存入父类接口 实现了这个接口的子类都可以存入这个集合 并且在返回的时候也只需要返回父类接口类型 他的所有子类都可以通过强转来调用这个方法
接口
//接口的作用:
//在享元模式的工厂中 只需要返回这个接口的类型 那么只要实现了这个接口的类都可以接收
public interface Shape {
void draw();
}
实现接口的子类
User
package bean;
public class Circle implements Shape{
private String name;
@Override
public void draw() {
System.out.println("Circle draw");
}
public Circle(String name) {
this.name = name;
}
}
Circle
package bean;
public class User implements Shape{
private String name;
public User(String name) {
this.name = name;
}
@Override
public void draw() {
System.out.println("user draw");
}
}
工厂
import java.util.HashMap;
//创建一个工厂,生成基于给定信息的实体类的对象。
public class FlyweightPattern {
//存放的位置
private static final HashMap<String, Shape> MAP = new HashMap<>();
//在这里为了易于理解 我写两个方法 分别代表两个类的返回
public static Shape getCircle (String name){
//先看看 传入方法的外部状态在集合中是否存在
Circle circle = (Circle) MAP.get(name);
//在集合中不存在代表这个外部状态是第一次创建
if(circle==null){
//创建新的对象
circle = new Circle(name);
//把新创建的对象存入集合 方便下次使用的时候调用
MAP.put(name, circle);
System.out.println("Circle: " + name);
}
return circle;
}
public static Shape getUser(String name){
//先看看 传入方法的外部状态在集合中是否存在
User user = (User) MAP.get(name);
//在集合中不存在代表这个外部状态是第一次创建
if(user==null){
//创建新的对象
user = new User(name);
//把新创建的对象存入集合 方便下次使用的时候调用
MAP.put(name, user);
System.out.println("User: " + name);
}
return user;
}
}
测试
import bean.User;
public class Demo{
private static final String colors[] =
{ "1", "3"};
public static void main(String[] args) {
//创建10次
for (int i = 0; i < 7; i++) {
System.out.println("----------第"+(i+1)+"次创建对象---------");
User user = (User) FlyweightPattern.getUser(getRandomName());
user.draw();
}
}
//模拟用户创建对象
private static String getRandomName() {
//通过随机数来悬着集合中的名称 来创建对象
return colors[(int)(Math.random()*colors.length)];
}
}
测试结果
----------第1次创建对象---------
User: 1
user draw
----------第2次创建对象---------(这些就是在集合中已经存在的 就直接调用)
user draw
----------第3次创建对象---------
User: 3
user draw
----------第4次创建对象---------(这些就是在集合中已经存在的 就直接调用)
user draw
----------第5次创建对象---------(这些就是在集合中已经存在的 就直接调用)
user draw
----------第6次创建对象---------(这些就是在集合中已经存在的 就直接调用)
user draw
----------第7次创建对象---------(这些就是在集合中已经存在的 就直接调用)
user draw