设计模式学习之享元模式

享元模式

运用共享技术有效地支持大量细粒度对象的复用,是一种对象结构型模式

类图

在这里插入图片描述

实现

抽象享元类

package design.flyweight.realize;

/*
 *
 *@author:zzf
 *@time:2020-12-21
 *
 */
public abstract class Flyweight {
    public abstract void operation(String extrinsicState);
}

具体享元类

package design.flyweight.realize;

/*
 *
 *@author:zzf
 *@time:2020-12-21
 *
 */
public class ConcreteFlyweight extends Flyweight {
    //内部状态intrinsicState作为成员变量,同一个享元对象的内部状态是一致的
    private String intrinsicState;

    public ConcreteFlyweight() {
    }

    public ConcreteFlyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }

    //外部状态extrinsicState在使用时由外部设置,不保存在享元对象中,即使是
    //同一对象,在每次调用时可以传入不同的外部状态
    @Override
    public void operation(String extrinsicState) {
        //具体业务
    }
}

享元工厂类

package design.flyweight.realize;

import java.util.HashMap;

/*
 *
 *@author:zzf
 *@time:2020-12-21
 *
 */
public class FlyweightFactory {
    //定义一个HashMap用于存储享元对象,实现享元池
    private HashMap flyweights=new HashMap();

    public Flyweight getFlyweight(String key){
        //如果对象存在,则直接从享元池获取
        if(flyweights.containsKey(key)){
            return (Flyweight) flyweights.get(key);
        }
        //如果对象不存在,先创建一个新的对象添加到享元池中,然后返回
        else {
            Flyweight fw=new ConcreteFlyweight();
            flyweights.put(key,fw);
            return fw;
        }
    }
}

应用实例

某软件公司要开发一个围棋软件,其界面效果如下图所示:
在这里插入图片描述
该软件公司开发人员通过对围棋软件进行分析发现,在图中,围棋棋盘中包含大量的黑子和白子,它们的形状、大小都一模一样,只是出现的位置不同而已。如果将每一个棋子都作为一个独立的对象存储在内存中,将导致该围棋软件在运行时所需内存空间较大,如何降低运行代价、提高系统性能是需要解决的一个问题。为了解决该问题,现使用享元模式来设计该围棋软件的棋子对象。
在这里插入图片描述
围棋棋子类,充当抽象享元类

package design.flyweight;

public abstract class IgoChessman {

	public abstract String getColor();

	public void display() {
		System.out.println("棋子颜色:" + this.getColor());
	}
}

具体享元类

package design.flyweight;

public class WhiteIgoChessman extends IgoChessman {

	public String getColor() {
		return "白色";
	}
}

package design.flyweight;

public class BlackIgoChessman extends IgoChessman {

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

围棋棋子工厂类,充当享元工厂类,使用单例模式设计

package design.flyweight;

import java.util.Hashtable;

public class IgoChessmanFactory {
	private static IgoChessmanFactory instance = new IgoChessmanFactory();
	private static Hashtable ht;//享元池

	private IgoChessmanFactory() {
		ht = new Hashtable<>();
		IgoChessman black, white;
		black = new BlackIgoChessman();
		ht.put("b", black);
		white = new WhiteIgoChessman();
		ht.put("w", white);
	}

	// 返回享元工厂类的唯一实例
	public static IgoChessmanFactory getIstance() {
		return instance;
	}

	// 通过key获取存储在Hashtable中的享元对象
	public static IgoChessman getIgoChessman(String color) {
		return (IgoChessman) ht.get(color);
	}

}

客户端

package design.flyweight;

public class Client {

	public static void main(String[] args) {
		IgoChessman black1, black2, black3, white1, white2;
		IgoChessmanFactory factory;

		// 获取享元工厂对象
		factory = IgoChessmanFactory.getIstance();

		// 通过享元工厂获取3颗黑子
		black1 = factory.getIgoChessman("b");
		black2 = factory.getIgoChessman("b");
		black3 = factory.getIgoChessman("b");
		System.out.println("判断两颗黑子是否相同:" + (black1 == black2));

		// 通过享元工厂获取2颗白子
		white1 = factory.getIgoChessman("w");
		white2 = factory.getIgoChessman("w");
		System.out.println("判断两颗白子是否相同:" + (white1 == white2));

		// 显示棋子
		black1.display();
		black2.display();
		black3.display();
		white1.display();
		white2.display();
	}
}

运行结果
在这里插入图片描述
该实例实现了享元工厂对象的唯一性

有外部状态的享元模式

新增需求:让相同的黑棋子、白棋子能够多次重复显示且位于一个棋盘的不同地方
解决方法:将棋子的位置定义为棋子的一个外部状态,在需要时再进行设置

增加坐标类

package design.flyweight;

/*
 *
 *@author:zzf
 *@time:2020-12-21
 *
 */
public class Coordinates {
    private int x;
    private int y;

    public Coordinates(int x, int y) {
        this.x = x;
        this.y = 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;
    }
}

修改显示方法display

package design.flyweight;

public abstract class IgoChessman {

	public abstract String getColor();

	public void display(Coordinates coord) {
		System.out.println("棋子颜色:" + this.getColor()+",棋子位置:"+coord.getX()+","+coord.getY());
	}
}

修改客户端代码

package design.flyweight;

public class Client {

	public static void main(String[] args) {
		IgoChessman black1, black2, black3, white1, white2;
		IgoChessmanFactory factory;

		// 获取享元工厂对象
		factory = IgoChessmanFactory.getIstance();

		// 通过享元工厂获取3颗黑子
		black1 = factory.getIgoChessman("b");
		black2 = factory.getIgoChessman("b");
		black3 = factory.getIgoChessman("b");
		System.out.println("判断两颗黑子是否相同:" + (black1 == black2));

		// 通过享元工厂获取2颗白子
		white1 = factory.getIgoChessman("w");
		white2 = factory.getIgoChessman("w");
		System.out.println("判断两颗白子是否相同:" + (white1 == white2));

		// 显示棋子
		black1.display(new Coordinates(1,2));
		black2.display(new Coordinates(3,4));
		black3.display(new Coordinates(1,3));
		white1.display(new Coordinates(2,5));
		white2.display(new Coordinates(2,4));
	}
}

运行结果
在这里插入图片描述

享元模式的优缺点

优点:
(1)极大地减少内存中对象地数量,使得相同或相似对象在内存中只保存一份,从而节约系统资源,提高系统性能
(2)其外部状态的相对独立,而且不会影响其内部状态,从而使享元对象可以在不同的环境中被共享

缺点:
(1)使系统变得复杂,需要分离出内部状态和外部状态,使得程序的逻辑复杂化
(2)需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长

适用环境

(1)一个系统有大量相同或者相似的对象,造成内存的大量耗费
(2)对象的大部分状态都可以外部化,可以将这些外部状态传入对象中
(3)需要多次重复使用享元对象

参考
Java设计模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值