享元模式是一种结构型设计模式,它通过共享来有效地支持大量细粒度的对象

享元模式是一种结构型设计模式,它通过共享来有效地支持大量细粒度的对象。享元模式的核心在于识别并提取对象中可以共享的部分,从而减少内存占用。下面是享元模式减少内存占用的几个关键步骤:

  1. 识别可共享的部分

    • 首先,分析对象结构,找出对象中哪些部分是可以共享的,哪些部分是不可共享的(即需要为每个对象独立存储的)。
  2. 创建享元类

    • 将可共享的部分提取出来,创建一个或多个享元类。这些享元类将包含对象的共享状态。
  3. 享元工厂

    • 创建一个享元工厂来管理享元对象的创建和共享。享元工厂负责检查请求的享元对象是否已经存在。如果存在,就直接返回该对象;如果不存在,就创建一个新的享元对象,并将其存储起来供后续请求使用。
  4. 使用享元

    • 在客户端代码中,使用享元工厂来获取享元对象。客户端不需要知道享元对象是如何创建和共享的,只需要通过享元工厂获取所需的享元对象即可。
  5. 分离不可共享状态

    • 对于每个具体的对象,除了共享状态外,还需要存储一些不可共享的状态。这些状态通常与享元对象一起存储,但它们是独立的,不会影响享元对象的共享。

通过这种方式,享元模式可以显著减少内存占用,因为它避免了创建大量相似对象的需要。例如,在围棋程序中,棋盘上的棋子可以作为享元对象,因为它们的颜色和形状是固定的,可以被多个棋局共享。每个棋局只需要存储棋子的位置信息,而不是棋子本身,从而节省了内存。

总结来说,享元模式通过共享可共享的部分,减少对象的创建数量,从而有效地减少了内存占用。
在开发一个网络围棋程序时,使用享元模式可以有效地减少内存占用,特别是在服务器资源有限的情况下。以下是如何使用享元模式来实现这个网络围棋程序的步骤:

1. 定义享元对象

首先,定义围棋棋子的享元对象。棋子可以是黑棋或白棋,这是可以共享的部分。每个棋子对象将包含颜色属性,这是不变的,因此可以被多个棋局共享。

class GoStone {
    private final String color;

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

    public String getColor() {
        return color;
    }
}

2. 创建享元工厂

创建一个享元工厂来管理棋子对象的创建和共享。这个工厂将检查请求的棋子是否已经存在,如果存在则返回该对象,否则创建一个新的棋子对象。

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

class GoStoneFactory {
    private final Map<String, GoStone> stones = new HashMap<>();

    public GoStone getStone(String color) {
        if (!stones.containsKey(color)) {
            stones.put(color, new GoStone(color));
        }
        return stones.get(color);
    }
}

3. 定义棋盘和游戏逻辑

棋盘和游戏逻辑需要使用棋子对象。每个棋局只需要存储棋子的位置信息,而不是棋子对象本身。

class GoBoard {
    private final GoStone[][] board;
    private final int size;

    public GoBoard(int size) {
        this.size = size;
        this.board = new GoStone[size][size];
    }

    public void placeStone(int row, int col, String color) {
        GoStone stone = new GoStoneFactory().getStone(color);
        board[row][col] = stone;
    }

    public GoStone getStoneAt(int row, int col) {
        return board[row][col];
    }
}

4. 管理游戏状态

每个玩家的游戏状态需要独立管理,但棋子对象可以共享。

class GoGame {
    private final GoBoard board;
    private String currentPlayer;

    public GoGame() {
        this.board = new GoBoard(19); // 围棋棋盘大小
        this.currentPlayer = "Black";
    }

    public void playMove(int row, int col) {
        board.placeStone(row, col, currentPlayer);
        switchPlayer();
    }

    private void switchPlayer() {
        currentPlayer = (currentPlayer.equals("Black")) ? "White" : "Black";
    }
}

5. 网络通信

通过网络通信模块,允许多个玩家联机下棋。每个玩家的操作通过网络发送到服务器,服务器处理后更新棋盘状态,并广播给所有玩家。

class GoServer {
    private final GoGame game;

    public GoServer() {
        this.game = new GoGame();
    }

    public void handleMove(String player, int row, int col) {
        game.playMove(row, col);
        // 广播更新给所有玩家
    }
}

通过这种方式,服务器只需要维护一个棋子对象池,而不需要为每个棋局创建新的棋子对象,从而大大节省了内存空间。同时,由于棋子对象是共享的,这也减少了对象创建和销毁的开销,提高了程序的性能。
在网络围棋程序中,服务器需要能够处理多个玩家的请求,包括玩家的移动、游戏状态的更新以及玩家之间的通信。以下是服务器处理多个玩家请求的一般步骤:

1. 玩家连接管理

服务器需要能够接受来自多个玩家的连接请求,并为每个玩家创建一个会话或连接对象。

class PlayerSession {
    private final String playerId;
    private final Socket socket;

    public PlayerSession(String playerId, Socket socket) {
        this.playerId = playerId;
        this.socket = socket;
    }

    public String getPlayerId() {
        return playerId;
    }

    public Socket getSocket() {
        return socket;
    }
}

2. 接收和解析请求

服务器需要监听来自玩家的请求,并解析这些请求以确定玩家想要执行的操作(如放置棋子、请求游戏状态等)。

void handleClientRequest(PlayerSession session) {
    try {
        ObjectInputStream ois = new ObjectInputStream(session.getSocket().getInputStream());
        String request = (String) ois.readObject();
        // 解析请求并执行相应操作
        processRequest(request, session);
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
}

3. 执行游戏逻辑

根据解析出的请求,服务器执行相应的游戏逻辑,如更新棋盘状态、检查游戏是否结束等。

void processRequest(String request, PlayerSession session) {
    if (request.startsWith("MOVE")) {
        String[] parts = request.split(",");
        int row = Integer.parseInt(parts[1]);
        int col = Integer.parseInt(parts[2]);
        game.playMove(row, col, session.getPlayerId());
        broadcastGameState();
    }
}

4. 广播更新

服务器需要将游戏状态的更新广播给所有连接的玩家,以确保所有玩家都能看到最新的游戏状态。

void broadcastGameState() {
    try {
        for (PlayerSession session : sessions) {
            ObjectOutputStream oos = new ObjectOutputStream(session.getSocket().getOutputStream());
            oos.writeObject(game.getGameState());
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

5. 管理游戏状态

服务器需要维护游戏的状态,包括当前玩家、棋盘状态、游戏是否结束等。

class GoServer {
    private final GoGame game;
    private final List<PlayerSession> sessions = new ArrayList<>();

    public GoServer() {
        this.game = new GoGame();
    }

    public void addPlayer(PlayerSession session) {
        sessions.add(session);
    }

    public void removePlayer(PlayerSession session) {
        sessions.remove(session);
    }

    public void handleClientRequest(PlayerSession session) {
        try {
            ObjectInputStream ois = new ObjectInputStream(session.getSocket().getInputStream());
            String request = (String) ois.readObject();
            // 解析请求并执行相应操作
            processRequest(request, session);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private void processRequest(String request, PlayerSession session) {
        if (request.startsWith("MOVE")) {
            String[] parts = request.split(",");
            int row = Integer.parseInt(parts[1]);
            int col = Integer.parseInt(parts[2]);
            game.playMove(row, col, session.getPlayerId());
            broadcastGameState();
        }
    }

    private void broadcastGameState() {
        try {
            for (PlayerSession session : sessions) {
                ObjectOutputStream oos = new ObjectOutputStream(session.getSocket().getOutputStream());
                oos.writeObject(game.getGameState());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

6. 错误处理和异常管理

服务器需要能够处理网络错误、玩家断开连接等异常情况,并确保游戏的稳定性。

通过上述步骤,服务器可以有效地处理多个玩家的请求,确保游戏的流畅运行。
下面是一个使用享元模式实现的网络围棋程序示例,该示例展示了如何通过共享围棋棋子对象来节省内存。

from typing import Dict, Tuple, List
import weakref

# 享元类:围棋棋子
class GoStone:
    def __init__(self, color: str):
        self.color = color  # 棋子颜色,如"black"或"white"
    
    def render(self, x: int, y: int) -> str:
        """渲染棋子,返回棋子信息"""
        return f"{self.color} stone at ({x}, {y})"

# 享元工厂:管理棋子池
class GoStoneFactory:
    _pool: Dict[str, GoStone] = weakref.WeakValueDictionary()
    
    @classmethod
    def get_stone(cls, color: str) -> GoStone:
        """获取棋子实例,颜色相同的棋子共享同一实例"""
        if color not in cls._pool:
            cls._pool[color] = GoStone(color)
        return cls._pool[color]

# 围棋棋盘类
class GoBoard:
    def __init__(self, size: int = 19):
        self.size = size
        self.board: Dict[Tuple[int, int], GoStone] = {}  # 存储落子信息
    
    def place_stone(self, x: int, y: int, color: str) -> None:
        """在指定位置落子"""
        if 0 <= x < self.size and 0 <= y < self.size:
            # 使用享元工厂获取棋子实例
            stone = GoStoneFactory.get_stone(color)
            self.board[(x, y)] = stone
            print(f"Placed {stone.render(x, y)}")
        else:
            print("Invalid position")
    
    def get_board_state(self) -> List[Dict]:
        """获取当前棋盘状态"""
        state = []
        for (x, y), stone in self.board.items():
            state.append({
                'position': (x, y),
                'color': stone.color
            })
        return state

# 玩家类
class Player:
    def __init__(self, name: str, color: str):
        self.name = name
        self.color = color
    
    def make_move(self, board: GoBoard, x: int, y: int) -> None:
        """玩家落子"""
        print(f"{self.name} ({self.color}) is placing a stone at ({x}, {y})")
        board.place_stone(x, y, self.color)

# 示例用法
if __name__ == "__main__":
    # 创建棋盘
    board = GoBoard()
    
    # 创建玩家
    player1 = Player("Alice", "black")
    player2 = Player("Bob", "white")
    
    # 模拟对弈过程
    player1.make_move(board, 9, 9)  # Alice 落黑子
    player2.make_move(board, 10, 9) # Bob 落白子
    player1.make_move(board, 9, 10) # Alice 落黑子
    player2.make_move(board, 10, 10) # Bob 落白子
    
    # 验证棋子实例的共享
    stone1 = GoStoneFactory.get_stone("black")
    stone2 = GoStoneFactory.get_stone("black")
    print(f"Are black stones the same instance? {stone1 is stone2}")  # 应该输出True
    
    stone3 = GoStoneFactory.get_stone("white")
    print(f"Are black and white stones different instances? {stone1 is not stone3}")  # 应该输出True    

这个实现通过享元模式有效减少了内存占用:

  1. GoStone类作为享元,只存储棋子的固有属性(颜色)
  2. GoStoneFactory管理棋子池,确保相同颜色的棋子只创建一个实例
  3. 使用弱引用存储棋子实例,允许在没有外部引用时被垃圾回收
  4. GoBoard类处理棋盘状态,每个位置只存储对享元对象的引用
  5. Player类表示玩家,负责执行落子操作

在实际网络围棋程序中,服务器可以为所有客户端共享使用同一套棋子实例,大幅降低内存占用。当多个玩家使用相同颜色的棋子时,这些棋子对象实际上是同一个实例。
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Bol5261

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

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

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

打赏作者

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

抵扣说明:

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

余额充值