Java设计模式之结构型模式 | 享元模式

41 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 19 天,点击查看活动详情

觉得对你有益的小伙伴记得点个赞+关注

后续完整内容持续更新中

希望一起交流的欢迎发邮件至javalyhn@163.com4

1. 享元模式定义

运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。

在享元模式中可以共享的相同内容称为内部状态(IntrinsicState),而那些需要外部环境来设置的不能共享的内容称为外部状态(Extrinsic State),由于区分了内部状态和外部状态,因此可以通过设置不同的外部状态使得相同的对象可以具有一些不同的特征,而相同的内部状态是可以共享的。 在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(Flyweight Pool)用于存储具有相同内部状态的享元对象。

2. 享元模式角色定义

  • Flyweight: 抽象享元类 Connection
  • ConcreteFlyweight: 具体享元类 ConnectionImpl(user,pwd,url)
  • UnsharedConcreteFlyweight: 非共享具体享元类ConnectionImpl(state)
  • FlyweightFactory: 享元工厂类;简单工厂,产品就一个Connection

3. 享元模式使用场景

  1. 数据库连接池
  2. 所有的池化技术

4. 享元模式的实现

给定以下池化技术的场景

image.png

AbstractWaitressFlyweight

/**
 * 可共享和不可共享状态
 */
public abstract class AbstractWaitressFlyweight {

    boolean canService = true;//能否服务

    //正在服务。   享元的不可共享属性留给外部进行改变的接口
    abstract void service();
    //服务完成。   享元的不可共享属性留给外部进行改变的接口
    abstract void end();

    public boolean isCanService() {
        return canService;
    }
}

BeautifulWaitress

import lombok.AllArgsConstructor;

/**
 * 具体享元类
 */
@AllArgsConstructor
public class BeautifulWaitress extends AbstractWaitressFlyweight{
    String id;//工号
    String name;//名字
    int age;//年龄
    //以上是不变的


    @Override
    void service() {
        System.out.println("工号:"+id+";"+name+" "+age+" 正在为您服务...");
        //改变外部状态
        this.canService = false;
    }

    @Override
    void end() {
        System.out.println("工号:"+id+";"+name+" "+age+" 服务结束...请给五星好评");

        this.canService = true;
    }
}

ZuDao

/**
 * 足道店:这相当于享元工厂
 *      店里面很多服务员。
 *
 * 享元和原型
 * 1、享元返回的是这个本人。
 * 2、原型返回的是克隆人。
 *
 */
public class ZuDao {

    private static Map<String,AbstractWaitressFlyweight> pool = new HashMap<>();
    //享元,池子中有对象
    static {
        BeautifulWaitress waitress =
                new BeautifulWaitress("1111","张三",18);


        BeautifulWaitress waitress2 =
                new BeautifulWaitress("9527","李四",20);


        pool.put(waitress.id,waitress);
        pool.put(waitress2.id,waitress2);
    }

    public void addWaitress(AbstractWaitressFlyweight waitressFlyweight){
        pool.put(UUID.randomUUID().toString(),waitressFlyweight);
    }

    public static AbstractWaitressFlyweight getWaitress(String name){
        AbstractWaitressFlyweight flyweight = pool.get(name);
        if(flyweight == null){
            for (AbstractWaitressFlyweight value : pool.values()) {
                //当前共享对象能否是否
                if(value.isCanService()){
                    return value;
                }
            };
            return null;
        }

        return flyweight;

    }

}

MainTest

public class MainTest {

    public static void main(String[] args) {

        //1、我
        AbstractWaitressFlyweight waitress = ZuDao.getWaitress("");
        waitress.service();
        System.out.println(waitress);
        //2、佟
        AbstractWaitressFlyweight waitress1 = ZuDao.getWaitress("");
        waitress1.service();
        System.out.println(waitress1);

        waitress1.end();
        //3、L
        AbstractWaitressFlyweight waitress2 = ZuDao.getWaitress("");
        System.out.println(waitress2);

    }
}

5. 享元模式优点

  • 享元模式大大减少了对象的创建,降低了程序内存的占用,提高效率

  • 享元模式提高了系统的复杂度.需要分离出内部状态和外部状态,而外部状态具有固化特性,不应该随着内部状态的改变而改变,这是我们使用享元模式需要注意的地方.

  • 使用享元模式时,注意划分内部状态和外部状态,并且需要有一个工厂类加以控制.享元模式经典的应用场景是需要缓冲池的场景,比如字符串常量池、数据库连接池