什么是享元模式(Flyweight)?我用Java模拟玩井字棋来告诉你!(Java版)

定义

享元模式(Flyeight):运用共享技术有效的支持大量细颗粒度的对象。

简单来说就是,共享对象、重复利用对象。

另外,享元模式还有四个角色、两个状态。

四个角色:

  1. 抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
  2. 具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。
  3. 非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
  4. 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。

两个状态:

  1. 内部状态:即不会随着环境的改变而改变的可共享部分。比如棋子的类型,不会随着环境改变而改变。
  2. 外部状态,指随环境改变而改变的不可以共享的部分。比如棋子的位置,随着人下的位置而改变。

享元模式的UML类图:
享元模式的UML类图

Java模式井字棋游戏

分析

需求明确了,咱们来分析一波。

下棋需要棋盘和棋子,这些都是井字棋的东西。——井字棋Tictactoe可作为接口或者抽象类
棋盘可以显示自己可下部分的编号——棋盘Chessboard需要有二维数组作为棋盘,并且作为共享部分
棋子类型有两种×、⭕(我输入的是朴实无华的圆圈,但是CSDN直接给变成这样了),两外棋子有自己的位置——棋子的类型(ChessPieces)是内部状态,棋子的位置是外部状态(ChessPiecesSite)需要分开写

再写一个工厂类作为池,负责给客户端提供棋盘和棋子

UML类图

井字棋UML类图

代码

Tictactoe——抽象享元角色(Flyweight)

// Tictactoe——井字棋
public interface Tictactoe {
	void show(ChessPiecesSite chessPiecesSite); 
}

Chessboard——具体享元角色(Concrete Flyweight)

public class Chessboard implements Tictactoe{

	public int[][] tic = {
			{1,2,3},
			{4,5,6},
			{7,8,9}
	};

	
	
	@Override
	public void show(ChessPiecesSite chessPiecesSite) {
		System.out.println("*****");
		System.out.println("获得棋盘,棋盘对应编号如下:");
		for (int i = 0; i < tic.length; i++) {
			for (int j = 0; j < tic.length; j++) {
				System.out.print(tic[i][j]);
			}
			System.out.println();
		}
		System.out.println("*****");
	}

}

Tictactoe——抽象享元角色(Flyweight)

public class ChessPieces implements Tictactoe{
	
	// 该棋子的类型
	public String type;
	
	

	public ChessPieces(String type) {
		super();
		this.type = type;
	}

	
	
	public String getType() {
		return type;
	}



	public void setType(String type) {
		this.type = type;
	}



	@Override
	public void show(ChessPiecesSite chessPiecesSite) {
		System.out.println("棋局编号:"+chessPiecesSite.getChessboardID());
		System.out.println("棋子类型:"+type);
		System.out.println("棋子位置:"+chessPiecesSite.getSite());
		System.out.println("---");
	}

}

ChessPiecesSite—— 非享元角色(Unsharable Flyweight)

public class ChessPiecesSite implements Tictactoe{
	// 该棋子所属棋局id
	public int chessboardID;
	// 该棋子的位置
	public int site;
	
	

	public ChessPiecesSite(int chessboardID, int site) {
		super();
		this.chessboardID = chessboardID;
		this.site = site;
	}



	public int getChessboardID() {
		return chessboardID;
	}



	public void setChessboardID(int chessboardID) {
		this.chessboardID = chessboardID;
	}



	public int getSite() {
		return site;
	}



	public void setSite(int site) {
		this.site = site;
	}



	@Override
	public void show(ChessPiecesSite chessPiecesSite) {
		System.out.println("所属棋盘"+chessboardID);
		System.out.println("棋子位置:"+site);
	}

}

TictactoeFactory——享元工厂角色(Flyweight Factory)

import java.util.HashMap;
import java.util.Map;

public class TictactoeFactory {

	private static Map<String,Tictactoe> pool = new HashMap<>();
	
	/**
	 * 获取棋盘对象
	 * @param chessboard
	 * @return
	 */
	public static Tictactoe getChessboard(String chessboard) {
		if(pool.get(chessboard)!=null) {
			return pool.get(chessboard);
		}
		pool.put(chessboard, new Chessboard());
		return pool.get(chessboard);
	}
	
	/**
	 * 获取棋子对象
	 * @param type
	 * @return
	 */
	public static Tictactoe getChessPieces(String type) {
		if(pool.get(type)!=null) {
			return pool.get(type);
		}
		pool.put(type, new ChessPieces(type));
		return pool.get(type);
	}
	
	/**
	 * 获取棋子对象
	 * @return
	 */
	public static int getPoolSize() {
		return pool.size();
	}
}

Client——客户端

public class Client {

	public static void main(String[] args) {
		Tictactoe chessboard = TictactoeFactory.getChessboard("chessboard");
		chessboard.show(null);
		Tictactoe chessPieces1 = TictactoeFactory.getChessPieces("×");
		chessPieces1.show(new ChessPiecesSite(1,5));
		Tictactoe chessPieces2 = TictactoeFactory.getChessPieces("⭕");
		chessPieces2.show(new ChessPiecesSite(1,2));
		Tictactoe chessPieces3 = TictactoeFactory.getChessPieces("×");
		chessPieces3.show(new ChessPiecesSite(1,7));
		Tictactoe chessPieces4 = TictactoeFactory.getChessPieces("⭕");
		chessPieces4.show(new ChessPiecesSite(1,3));
		Tictactoe chessPieces5 = TictactoeFactory.getChessPieces("×");
		chessPieces5.show(new ChessPiecesSite(1,1));

		System.out.println("池大小:"+TictactoeFactory.getPoolSize());
		System.out.println("持⭕的玩家输了~~重新开始一局!!");

		Tictactoe chessboard2 = TictactoeFactory.getChessboard("chessboard");
		chessboard2.show(null);
		Tictactoe chessPieces21 = TictactoeFactory.getChessPieces("×");
		chessPieces21.show(new ChessPiecesSite(2,5));
		Tictactoe chessPieces22 = TictactoeFactory.getChessPieces("⭕");
		chessPieces22.show(new ChessPiecesSite(2,6));
		Tictactoe chessPieces23 = TictactoeFactory.getChessPieces("×");
		chessPieces23.show(new ChessPiecesSite(2,7));
		Tictactoe chessPieces24 = TictactoeFactory.getChessPieces("⭕");
		chessPieces24.show(new ChessPiecesSite(2,3));
		Tictactoe chessPieces25 = TictactoeFactory.getChessPieces("×");
		chessPieces25.show(new ChessPiecesSite(2,9));

		System.out.println("池大小:"+TictactoeFactory.getPoolSize());
		System.out.println("持⭕的玩家又输了!!");

	}
}

/ 我的圆圈本来是朴实无华的。。。。像这样:
叉和圆圈

运行结果

*****
获得棋盘,棋盘对应编号如下:
123
456
789
*****
棋局编号:1
棋子类型:×
棋子位置:5
---
棋局编号:1
棋子类型:⭕
棋子位置:2
---
棋局编号:1
棋子类型:×
棋子位置:7
---
棋局编号:1
棋子类型:⭕
棋子位置:3
---
棋局编号:1
棋子类型:×
棋子位置:1
---
池大小:3
持⭕的玩家输了~~重新开始一局!!
*****
获得棋盘,棋盘对应编号如下:
123
456
789
*****
棋局编号:2
棋子类型:×
棋子位置:5
---
棋局编号:2
棋子类型:⭕
棋子位置:6
---
棋局编号:2
棋子类型:×
棋子位置:7
---
棋局编号:2
棋子类型:⭕
棋子位置:3
---
棋局编号:2
棋子类型:×
棋子位置:9
---
池大小:3
持⭕的玩家又输了!!

井字棋玩的少的人,可能看不出来,我再图形化展示一下
第一局:
第一局
第二局:
第二局

我们可以看到,池子里边放了一个棋盘、两个棋子对象后,就不再放新的对象,因为一直在复用。

个人理解:关于数据库连接池

相信大家学习享元模式,经常听到,什么什么池应用了享元模式,但是仔细一想,又不知道在哪里用了,一脸懵逼。下边就说一下个人理解。
先来理解一下池是什么。

生活中的小水池,池水资源可以供大家共同使用。

在咱们这个井字棋里边,有个pool的Map集合,里边放的棋盘、棋子资源,共调用者共同使用。其实,咱们的对象基本已经确定又3个了,不用集合也可以,提前声明好,需要用的时候就实例化。也可以。
所以说,咱们这个享元模式的案例中,有用池的思想。

现在应该理解池是什么了。

那么数据库连接池是怎们用享元模式呢?

分析一下数据库链接对象:每个链接的账号、密码、端口、地址等数据都是一样的。每次实例化链接对象时,都会把这些重复的信息再在内存里边生成。造成内存浪费。

现在,咱们把这些共同的链接信息单独写个类,实例化好。每次新建连接时,都来此对象取走信息进行连接。

相对来说,我们每次实例化连接时,占用的内存空间更少了。

重复使用数据库连接信息对象,这里使用了享元模式。

至于把所有的连接存到容器,动态生成或者销毁时属于池的思想了。

个人学习总结,如果有不对的地方,希望大佬指正

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值