设计模式之享元模式的实现

(一)、享元模式的简单介绍

享元模式:类似于池技术,实现对象的复用。

好处:

1)、减少内存的使用 ,避免出现大量重复的创建销毁对象的场景

2)、外部状态相对独立,而且不会影响其内部状态 ,元对象可以在不同的环境中 被共享

享元模式的实现:把一个对象的状态分成内部状态和外部状态 ,内部状态即是不变的 ,外部状态是变化的 ,通过共享不变的部分 ,达到减少对象数量并节约内存 的目的。

享元模式应用:

当系统中多处需要同一组信息时 ,把这些信息封装到一个对象中 ,然后对该对象进行缓存 。

享元模式 同样要求创建一个或一组对象,通过工厂方法生成对象的 。

享元模式的三种角色

1)、抽象享元模式(flyweight)

享元对象抽象基类或者接口,  同时定义出对象的外部状态和内部状态的接口或

实现。

2)、具体享元模式(concreteflyweight)

实现抽象角色定义的业务 ,角色的内部状态处理应该与环境无关 

    不能出现会有一个操作改变内部状态,同时修改了外部状态。 

3)、享元工厂(flyweightfctory)

负责管理享元对象池和创建享元对象  

(二)、实现享元模式的步骤

1、享元抽象类

2、享元具体类

3、享元工厂类

4、使用类

(三)、利用享元模式模拟围棋游戏

/**
围棋游戏
 * --: 围棋分白子和黑子,用户在玩围棋时会用到多个黑子和白子
 * 模拟下棋操作
 *  --:此时,出现了一个问题:
 *      每当用户出一个棋子就会重行创建一个棋对象,如果很多用户在下棋,那么,服务器就会有很对棋对象,占用服务器的内存
 *
 *  --:发现规律,用户操作棋子,棋子的颜色(黑色和白色)不会变化,变棋子的位置发生化。
 *      解决问题:
 *      所有的用户使用同一个棋子对象
 */

享元抽象类:

/**
 * 围棋
 *  --: 棋子的属性
 *       颜色:黑色/白色,是不变的。
 *       坐标:x,y ,变化的。
 */
public abstract class Chess {
    //棋子的颜色为内部状态
    private String color;
    /**
     * 享元模式,将可变的东西转为外部状态。
     */
    //private int x;
    //private int y;

    public abstract String getColor();

    //Coordinates coord 为外部状态,通过外部注入的方式生成
    public void display(Coordinates coord){
        System.out.println("棋子的颜色:"+ this.getColor() +"-->棋子所在的位置"+coord.getX()+","+coord.getY());
    }
}

享元具体类:

public class BlackChess extends Chess{

    @Override
    public String getColor() {
        return "黑色";
    }
}

public class WhiteChess extends Chess{
    @Override
    public String getColor() {
        return "白色";
    }
}

外部状态类:

/**
 * 围棋类的外部状态类
 */
public class Coordinates {
    private int x;
    private int y;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public Coordinates(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public Coordinates() {
    }
}

享元工厂类:

/**
 * 创建棋子的工厂,工厂生产的产品不重复
 *   ---:1. 通过工厂,可以创建一批同类对象。
 *        2. 通过过池(集合),可以复用对象。
 */
public class ChessFactory {
    /**
     * 将棋子存放在一个集合中,保证生产的产品不重复
     */
    private static Map<String, Chess> pool = new HashMap<>();

    /**
     *  接单时先根据产品标识,判断产品是否重复
     */
    public static Chess getChess(String color){
        Chess chess = null;
        if(pool.containsKey(color)){
            return pool.get(color);
        }
        //如果池中没有所要对象则重新创建对象,并放入池中
        if(color == "b"){
            chess = new BlackChess();
            pool.put(color, chess);
            return chess;
        }
        if(color == "w"){
            chess = new WhiteChess();
            pool.put(color, chess);
            return chess;
        }
        return chess;
    }
}

使用类:

/**
 * 通过工厂来创建棋子
 *
 */
public class Client2 {
    public static void main(String[] args) {
        //通过工厂创建一个黑棋对象
        Chess blackChess1 = ChessFactory.getChess("b");
        blackChess1.display(new Coordinates(1,3));
        //从池中取出黑棋对象
        Chess blackChess2 = ChessFactory.getChess("b");
        blackChess2.display(new Coordinates(3,6));
        System.out.println(blackChess1 == blackChess2);

        Chess whiteChess1 = ChessFactory.getChess("w");
        whiteChess1.display(new Coordinates(1,1));
        Chess whiteChess2 = ChessFactory.getChess("w");
        whiteChess2.display(new Coordinates(2, 2));
        System.out.println(whiteChess1 == whiteChess2);

    }
}

结果:

棋子的颜色:黑色-->棋子所在的位置1,3
棋子的颜色:黑色-->棋子所在的位置3,6
true
棋子的颜色:白色-->棋子所在的位置1,1
棋子的颜色:白色-->棋子所在的位置2,2
true

(四)、利用享元模式模拟人事管理系统查询

需求:
*  --: 一个SAAS(software AS A Service)软件应用模式的人事管理系   统,该系统提供给甲、乙、丙三家公司使用
*       1.甲、乙、丙各有100名员工,员工可以登录系统,查询自己的工资报表。
*       2.甲、乙、丙公司各有自己对应的数据库,可以为甲、乙、丙提供对应的查询接口。
		3.创建各公司对应的查询接口实例,公司的员工查询工资时使用同一个实例。

享元抽象类:

/**
 *  抽象享元类
 *
 *  需求:
 *  --: 一个SAAS(software AS A Service)软件应用模式的人事管理系统,该系统提供给甲、乙、丙三家公司使用
 *       1.甲、乙、丙各有100名员工,员工可以登录系统,查询自己的工资报表。
 *       2.甲、乙、丙公司各有自己对应的数据库,可以为甲、乙、丙提供对应的查询接口。
 *
 */

public interface IReportManager {
    /**
     * 该接口的作用是创建报表
     */
    public String  createReport(String employeeName);
}

享元具体类:

/**
 * 创建员工工资报表
 */
public class FiniancialReportManager implements IReportManager{

    /**
     *  tenantId : 享元对象的内部状态, 使用该系统的公司名称
     */
    private String tenantId = null;

    FiniancialReportManager(String tenantId){
        this.tenantId = tenantId;
    }

    /**
     * employeeName: 享元模式的外部状态
     */
    @Override
    public String createReport(String employeeName) {
        return "create FiniancialReport:"+employeeName;
    }
}

/**
 * 享元具体类
 */
public class EemployeeReportManager implements IReportManager{
    private String tenantId = null;
    EemployeeReportManager(String tenantId){
        this.tenantId = tenantId;
    }

    @Override
    public String createReport(String employeeName) {
        return "create EemployeeReport:" + employeeName;
    }
}

享元工厂类:

public class ReportManangerFactory {
    //存放查询工资报表的集合
    Map<String, IReportManager> financialMap = new HashMap<>();
    //存放查询员工信息报表的集合
    Map<String, IReportManager> employeeMap = new HashMap<>();

    /**
     * 获取工资报表接口对象
     * @return
     */
    public IReportManager getFinancialReport(String tenantId){
        if(financialMap.containsKey(tenantId)){
            return financialMap.get(tenantId);
        }else{
            FiniancialReportManager finiancialReportManager = new FiniancialReportManager(tenantId);
            financialMap.put(tenantId, finiancialReportManager);
            return finiancialReportManager;
        }
    }

    /**
     * 获取员工信息列表对象
     * @param tenantId
     * @return
     */
    public IReportManager getEmployeeReport(String tenantId){
        if(employeeMap.containsKey(tenantId)){
            return employeeMap.get(tenantId);
        }else{
            EemployeeReportManager employeeReportManager = new EemployeeReportManager(tenantId);
            employeeMap.put(tenantId, employeeReportManager);
            return employeeReportManager;
        }
    }
}

使用类:

public class Client {
    public static void main(String[] args) {
        //创建享元对象工厂
        ReportManangerFactory reportManangerFactory = new ReportManangerFactory();
        //A公司员工甲查询工资,创建A公司的报表查询接口
        IReportManager reportManagerA = reportManangerFactory.getFinancialReport("A");
        //使用查询报表功能
        String result = reportManagerA.createReport("李雷");
        System.out.println(result);

        //A公司的员工乙查询工资,也创建A公司的报表查询接口
        IReportManager reportManagerReA = reportManangerFactory.getFinancialReport("A");
        //判断两个查询接口是否是同一个对象
        System.out.println(reportManagerA == reportManagerReA);
        String result1 = reportManagerReA.createReport("migng");
        System.out.println(result1);
    }
}

结果:

create FiniancialReport:李雷
true
create FiniancialReport:migng
金麟岂能忍一世平凡 飞上了青天 天下还依然
原文地址:https://www.cnblogs.com/Auge/p/11580221.html