设计模式 --享元模式

226 阅读3分钟

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。

1.享元模式的简介

享元(Flyweight)模式:“享”即使共享的意思,“元”即表示对象,所以从字面意思我们可以理解为共享对象的意思。它主要通过共享技术,尝试共享大量细粒度的对象,减少大量相同对象的创建。减少大量相同对象的内存占用,提高系统资源利用率,能一定程度上避免内存溢出。

它的主要应用在池上,如缓存池,String常量池,线程池等,当池中有我们需要的对象,我们可以直接拿出来使用,避免重复创建,降低系统开销。当池中没有的时候,我们可以自己创建一个放入池中,共享给别的程序使用。

  1. 前面我们说了一个细粒度对象,那么何为细粒度。

    把一个对象分的更细,这里指分出它的内部状态和外部状态,这里引申出来两个概念,内部状态和外部状态

    • 内部状态:一个对象固有的,不会随外部状态改变的信息,可以共享的,比如一个人的两个眼睛,一个鼻子这些是无法改变的,可以称之为内部状态。

    • 外部状态:及一个对象会随外部状态改变的信息,不可共享。如人的工作公司,收入等。

2.享元模式结构图

image.png

  1. 抽象享元角色(Flyweight):是所有的具体享元类的基类,它负责定义享元角色的外部状态的接口和内部状态。
  2. 具体享元角色(Concrete Flyweight):实现抽象享元角色中所定义的相关接口。
  3. 非享元角色(Unsharable Flyweight):即享元角色不可以共享的外部状态,它可以以参数的形式注入具体享元对应的方法中。
  4. 享元工厂角色(Flyweight Factory):负责创建和管理享元角色。当客户端想要获取一个享元对象时,他会先检査工厂中是否存在符合要求的享元对象,如果存在则直接提供;如果不存在的话,则创建一个新的。

3.代码举例

  1. 抽象享元角色
public abstract class Flyweight {

   public abstract void use(OutRole outRole);//抽象方法
}
  1. 具体享元角色
//具体享元角色
public class ConcreteFlyweight extends Flyweight {

   //共享的部分,内部状态
   private String type = "";

   
   //构造器
   public ConcreteFlyweight(String type) {
      
      this.type = type;
   }


   @Override
   public void use(OutRole outRole) {
      // TODO Auto-generated method stub
      System.out.println("类型为:" + type + " 使用的外部角色是" + outRole.getName());
   }
   
   
}

3.外部状态(这里也可以做成抽象的)

public class OutRole {
   
   private String name;

   
   public OutRole(String name) {
      super();
      this.name = name;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
   
   
}
  1. 享元工厂
// 享元工厂类,根据需要返回一个享元
public class FlyweightFactory {

   
   //集合, 充当池的作用,保存已创建的享元类
   private HashMap<String, ConcreteFlyweight> pool = new HashMap<>();
   
   //根据类型,返回一个享元类, 如果没有就创建一个享元类,并放入到池中,并返回
   public Flyweight getFlyweightCategory(String type) {
      if(!pool.containsKey(type)) {
         //就创建一个网站,并放入到池中
         pool.put(type, new ConcreteFlyweight(type));
      }
      
      return (Flyweight)pool.get(type);
   }
   
   //获取享元类的总数 (池中有多少个享元类)
   public int getWebSiteCount() {
      return pool.size();
   }
}
  1. 客户端
public static void main(String[] args) {
   // TODO Auto-generated method stub

   // 创建一个工厂类
   FlyweightFactory factory = new FlyweightFactory();

   // 客户要一个以新闻形式发布的网站
   Flyweight flyweight = factory.getFlyweightCategory("测试1");


   flyweight.use(new OutRole("outRole1"));

   // 客户要一个以博客形式发布的网站
   Flyweight flyweight1 = factory.getFlyweightCategory("测试2");

   flyweight1.use(new OutRole("outRole2"));

   
   System.out.println("网站的分类共=" + factory.getWebSiteCount());
}

4. 应用案列

java中的,int常量池(-128 - 127),string常量池,线程池,数据库连接池,还有一些缓存,都是基于享元模式的应用案例。 这里我就不一一举例,大家可以自己去看看。