分析:
五子棋同围棋一样,包含多个“黑”或“白”颜色的棋子,所以用享 元模式比较好。
模式的应用场景
享元模式是通过减少内存中对象的数量来节省内存空间的,所以以 下几种情形适合采用享元模式
系统中存在大量相同或相似的对象,这些对象耗费大量的内存资源。
大部分的对象可以按照内部状态进行分组,且可将不同部分外部化, 这样每一个组只需保存一个内部状 态。
由于享元模式需要额外维护一个保存享元的数据结构,所以应当在有 足够多的享元实例时才值得使用 享元模式。
拓展思路
◼ 享元模式中,其结构图通常包含可以共享的部分和不可以共享的部分。 在实际使用过程中,有时候会稍加改变,即存在两种特殊的享元模式: 单纯享元模式和复合享元模式。
◼ 单纯享元模式:这种享元模式中的所有的具体享元类都是可以共享的,不存 在非共享的具体享元类
◼ 单纯享元模式:这种享元模式中的有些享元对象是由一些单纯享元对象组合 而成的,它们就是复合享元对象。虽然复合享元对象本身不能共享,但它们可 以分解成单纯享元对象再被共享
拓展思路
◼ 单纯享元模式:这种享元模式中的所有的具体享元类都是可以共享的,不存 在非共享的具体享元类
结构图说明:
本实例中的棋子(ChessPieces)类是抽象享元角色,它包含了一个落子的DownPieces(Graphics g,Point pt) 方 法;白子(WhitePieces)和黑子(BlackPieces)类是具体享元角色,它实现了落子方法;Point 是非享元角色, 它指定了落子的位置;WeiqiFactory 是享元工厂角色,它通过 ArrayList 来管理棋子,并且提供了获取白子或者黑 子的 getChessPieces(String type) 方法;客户类(Chessboard)利用 Graphics 组件在框架窗体中绘制一个棋盘, 并实现 mouseClicked(MouseEvent e) 事件处理方法,该方法根据用户的选择从享元工厂中获取白子或者黑子并 落在棋盘上。
代码
棋子:
import java.awt.Graphics;
import java.awt.Point;
/**
* 抽象享元角色 棋子
* @author 17717
*
*/
public interface ChessPieces {
void downPieces(Graphics graphics,Point point);
}
具体的享元角色 白棋:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
/**
* 具体的享元角色 白棋
* @author 17717
*
*/
public class BlackPieces implements ChessPieces{
@Override
public void downPieces(Graphics graphics, Point point) {
graphics.setColor(Color.white);//设置颜色
graphics.fillOval(point.x, point.y, 30, 30);
}
}
具体的享元角色 黑棋
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
/**
* 具体的享元角色 黑棋
* @author 17717
*
*/
public class WhitePieces implements ChessPieces{
@Override
public void downPieces(Graphics graphics, Point point) {
graphics.setColor(Color.black);//设置颜色
graphics.fillOval(point.x, point.y, 30, 30);
}
}
享元工厂角色
import java.util.HashMap;
import java.util.Map;
/**
* 享元工厂角色
* @author 17717
*
*/
public class WuziqiFactory {
private Map<String,ChessPieces> map=new HashMap<String,ChessPieces>();
public WuziqiFactory() {
ChessPieces white=new WhitePieces();
ChessPieces black=new BlackPieces();
map.put("white",white);
map.put("black",black);
}
public ChessPieces getChessPieces(String type) {
return map.get(type);
}
}
棋盘
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
public class ChessBoard extends MouseAdapter{
private WuziqiFactory factory;
private JFrame frame;
private Graphics graphics;
private JRadioButton wz,bz;
private final int x=50;
private final int y=50;
private final int w=40;//小方格的宽度和高度
private final int rw=600;//棋盘的宽度和高度
public ChessBoard() {
this.factory = new WuziqiFactory();
this.frame =new JFrame("享元模式在五子棋中的应用");
this.frame.setBounds(100,100,500,500);//设置窗体界限
this.frame.setResizable(false);
this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);;
this.frame.setVisible(true);
this.frame.setLocationRelativeTo(null);
//创建按钮组件
JPanel southJp=new JPanel();
this.frame.add(BorderLayout.SOUTH,southJp);
this.wz=new JRadioButton("白子",true);//为真时选中
this.bz=new JRadioButton("黑子");
ButtonGroup group=new ButtonGroup();
group.add(this.wz);
group.add(this.bz);
southJp.add(this.wz);
southJp.add(this.bz);
//创建棋盘组件
JPanel centerJp=new JPanel();
centerJp.setLayout(null);
centerJp.setSize(500,500);
centerJp.addMouseListener(this);//增加点击事件
this.frame.add(BorderLayout.CENTER,centerJp);
try {
Thread.sleep(5000);
}catch (Exception e) {
System.out.println("");
}
this.graphics=centerJp.getGraphics();
this.graphics.setColor(Color.BLUE);
this.graphics.drawRect(x, y, rw, rw);
for(int i=0;i<10;i++) {
//绘制竖线
graphics.drawLine(x+(i*w), y, x+(i*w), y+rw);
//横线
graphics.drawLine(x, y+(i*w), x+rw, y+(i*w));
}
}
@Override
public void mouseClicked(MouseEvent e) {
Point pt=new Point(e.getX()-15,e.getY()-15);
String type="black";
if(this.wz.isSelected()) {
type="white";
}
ChessPieces pieces=factory.getChessPieces(type);
pieces.downPieces(this.graphics, pt);
}
}
测试类
public class App {
public static void main(String[] args) {
new ChessBoard();
}
}
总结
⚫ Flyweight采用对象共享的做法来降低系统中对象的个数,从而降低 细粒度对象给系统带来的内存压力。在具体实现方面,要注意对象状 态的处理。
⚫ 对象的数量太大从而导致对象内存开销加大——什么样的数量才算大 ?这需要我们仔细的根据具体应用情况进行评估,而不能凭空臆断。