设计模式之享元模式

1.简要概述

  • 享元模式也叫作蝇量模式,就是以共享的方式高效的支持大量细粒度对象的重用,这些对象一部分内部状态是相同的。

  • 享元模式中的享元对象能做到共享的关键是区分了内部状态和外部状态,内部状态可以共享而且不会随环境变化而改变,外部状态不可以共享但会随环境变化而改变。

    💡举例:在围棋中,我们知道棋子的颜色分为黑色和白色,每个棋子所在棋盘的位置都不相同,所以这里棋子的颜色就可以看作是内部状态(可共享的),而棋子的位置就可以看作是外部状态(不可共享的)。

  • 享元模式能够解决重复对象的内存浪费问题,当系统中存有大量相似对象的时候,可以利用享元模式创建一个相关的缓冲池。如果需要该对象时,只需从缓冲池中获取即可,不必反复创建对象。

  • 享元模式最经典的应用场景就是池技术,比如:字符串常量池、数据库连接池等等。

2.模式结构

👉通常由一个享元工厂类( 负责创建并管理共享的享元对象,对外提供获取该对象的方法 ),一个享元抽象类或者接口( 负责声明公共方法,向外界提供对象的共享的内部状态,同时设置特有的外部状态 ),多个具体享元实现类( 负责实现具体的外部状态方法,并为内部状态提供成员变量进行存储 ),多个具体的非共享享元实现类( 定义不能够被共享的子类实现,不会出现在享元工厂 ),一个客户类( 负责通过享元工厂类获取指定的享元对象实例)共同组成。

请添加图片描述

3.实现代码

举例 💡 :假设我们现在要对围棋中的棋子通过对象进行表示,那么就可以使用享元模式来减少对象的重复创建,减少系统资源的利用。

棋子接口(享元抽象类)

public interface ChessFlyWeight {
	String getColor();
    
	void display(ChessLocation location);
}

棋子(具体享元实现类)

class Chess implements ChessFlyWeight{
    private String color;

    public Chess(String color) {
        this.color = color;
    }

    @Override
    public String getColor() {
        return color;
    }

    @Override
    public void display(ChessLocation location) {
        System.out.println("位置为:("+location.getX()+","+location.getY()+")");
    }
}

棋子位置(非共享享元实现类)

public class ChessLocation {
	private int x;
	private int y;
	
	public ChessLocation(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;
	}
}

棋子工厂(享元工厂类)

public class ChessFactory {
    private static Map<String, Chess> chessMap = new HashMap<String, Chess>();

    public static ChessFlyWeight getChess(String color) {
        if (chessMap.containsKey(color))
        {
            return chessMap.get(color);
        } else {
            Chess chess = new Chess(color);
            chessMap.put(color, chess);
            
            return chess;
        }
    }
}

客户类

// 测试客户端
public class ChessClient{
    public static void main(String[] args) {
        ChessFlyWeight chess1 = ChessFactory.getChess("黑棋");
		ChessFlyWeight chess2 = ChessFactory.getChess("黑棋");
		
		System.out.println(chess1 == chess2); // true
		chess1.display(new ChessLocation(10, 10)); // 位置为(10,10)
        chess2.display(new ChessLocation(14, 15)); // 位置为(14,15)
		
        ChessFlyWeight chess3 = ChessFactory.getChess("白棋");
        
        System.out.println(chess1.getColor()); // 黑棋
        System.out.println(chess3.getColor()); // 白棋
    }
}

4.优点好处

  • 极大的减少了内存中对象的数量
  • 相同或相似的对象在内存中只存一份,极大的节约资源,提高了系统性能
  • 使用过程中,外部状态相对独立,不影响内部状态。

5.缺点弊端

  • 由于模式本身较为复杂,使程序逻辑复杂化,提高了系统的复杂度。
  • 为了节省内存,需要共享内部状态,分离外部状态,而读取外部状态使运行时间变长,所以用时间换取了空间。

6.应用场景

  • 当系统中存在很多完全相同或者相似对象的时候使用,用来节省内存。
  • 当系统中有大量对象,这些对象消耗大量内存,并且对象的状态大部分可以外部化的时候使用。

7.应用示例

JDK源码中的Integer类

请添加图片描述

请添加图片描述

从上面的代码中我们我可以看出,在Integer类的valueOf方法内部进行了一个判断,如果i的值在指定的范围区间,那就直接从缓存中取值,否则创建新的对象。所以这里就用到了享元模式,来提高系统的性能。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程小吉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值