网络游戏开发中的领域模型

    一直以来我都在思考网络游戏开发的OO模式。如何将领域建模运用到网络游戏这种异步项目中。在我的网络游戏架构中,为了避免多线程引发的诸多问题,逻辑服务模块采用单线程方式,考虑到单线程下阻塞模式会严重影响服务器的性能,因此采用了异步方式进行逻辑的通讯。我想大多的网络游戏开发应该都是采用异步方式。但异步方式,很容易将一个原本完整的逻辑,折分成一个一个request、response等网络命令,服务器端将一些逻辑代码写在收到指令的地方,另一些写在业务类中,同样在收到指令的地方调用。没有一种清晰的思路来区分哪些逻辑该和异步的收发混在一起,哪些逻辑该放在领域层。

    昨天重新看了一些DDD(Domain Driven-Desgin)的文章,复习了一个Entity、Value、Service的概念,下面以玩家在商店购买一个道具为例,整理了一下思路。(由于只是快速草稿,因此很多语法细节是错误的)

 

 

――――――――――应用层―――――――――――― 

// 客户端的购买道具逻辑代理 
class ShoppingAgent : public ServiceAgent 
{ 
public: 
	// 发出购买某道具的 

	void requestBuyItem(int itemId, int qty) 
	{ 
		BuyItemRequest request(itemId, qty); 
		send(request); 
	} 
	void onBuyItemResponse(BuyItemResponse response) 
	{ 
		if(response.errorId == NO_ERROR) 
			m_listener->onBuyItemOk(); 
		else 
			m_listener->onBuyItemFail(); 
	} 
protected: 
	ShoppingListener m_listener; 
} 

// 服务端购买道具的逻辑服务
class ShoppingService : public Service 
{ 
public: 
	// 响应购买道具的请求 

	void onBuyItemRequest(BuyItemRequest r) 
	{ 
		BuyItemResponse response; 
		Shopping shopping; 
		try 
		{ 
			shopping.buyItem(r.playerId, r.shopId, r.itemId, r.qty); 
		} 
		catch(ShoppingException e) 
		{ 
			// 购买失败的错误ID会跟随response发回给客户端 
			response.errorId = e.errorId; 
		} 
		send(response); 
	} 
} 

 

   

    应用层,在这里主要负责对网络的异步通讯封装。ShoppingService作为服务在部署在服务器上,而ShoppingAgent作为访问服务的一个接口部署在客户端。对于客户端的应用上层,不需要调用到任何通讯指令,全部委托给ShoppingAgent。异步的结果,皆通过观察者模式,通知给上层。
   

 

 

――――――――――领域层―――――――――――― 
 
// 购买道具的服务 
//(对应Erice Evans 在Domain 中的service)

class Shopping 
{ 
public: 
	// 购买道具 

	void buyItem(int playerId, int shopId, int itemId, int qty) 
	{ 
		Shop shop = m_respository.getShop(shopId); 
		Player player = m_respository.getPlayer(playerId); 

		// 验证商店是否有要购买的道具 

		validateShopHasItem(shopId, itemId, qty); 
		// 取出道具价格 

		int amount = shop.getPrice(itemId, qty); 
		// 验证玩家是否有足够的钱 
		validatePlayerHasMoney(playerId, amount); 
		// 验证玩家背包是否有足够空间 
		validatePlayerHasSpace(playerId, itemId, qty); 

		// 玩家收到一定数量的道具 
		player.receiveItem(itemId, qty); 
		// 玩家付款 
		player.pay(amount); 
	} 

protected: 
	void validateShopHasItem(shopId, itemId, qty) 
	{ 
		Shop &shop = m_respository.getShop(shopId); 
		if(shop.hasItem(itemId, qty)) 
			throw new ShopHasNoItemException(); 
	} 

	void validatePlayerHasSpace(int playerId, int itemId, int qty) 
	{ 
		Player &player = m_respository.getPlayer(player); 
		Item &item = m_itemRespository.getItem(itemId); 

		if(player.getBag().getSpaceAvailabe() < item.getCapability() * qty) 
		{ 
			throw new NoEnoughSpaceException(); 
		} 
	} 

	void validatePlayerHasMoney(int playerId, int price) 
	{ 
		Player &player = m_respository.getPlayer(player); 

		if(player.hasMoney(price)) 
		{ 
			throw new NoEnoughMoneyException(); 
		} 
	} 
} 

// 商店,提供道具的购买,对道具定价(不同商店卖的东西不同) 
//(对应Erice Evans 在Domain 中的entity)

class Shop 
{ 
public: 
	int getPrice(int itemId, int qty) 
	{ 
		// …查找商品价格并乘上数量 
	} 

	bool hasItem(int itemId, int qty) 
	{ 
		// …查找商品 
	} 
} 

// 玩家 
//(对应Erice Evans 在Domain 中的entity) 
class Player 
{ 
public: 
	void receiveItem(int itemId, int qty) 
	{ 
		getBag()->pack(itemId, qty); 
	} 

	void pay(int money) 
	{ 
		m_money -= money; 
	} 
} 

// 资源仓库,由于是例子,所以先写到一块来

class Respoistory 
{ 
public: 
	Shop& getShop(int id) 
	{ 
	} 

	Player& getPlayer(int id) 
	{ 
	} 

	Item& getItem(int id) 
	{ 
	} 
} 

 

   

    Shopping 同Shop的分离,是我重新看DDD文章后的重大改变。不然之前一直困惑于buyItem()中会对于玩家的一些逻辑操作,似乎不应该是shop这个领域Entity的职责。

    Shopping同ShoppingService是分离的,在我的概念里,领域层应该足够的单纯,应该不用知道异步通讯这回事。对于这两者的职责我是这样分配的:Shopping负责真正的购买逻辑,协调玩家、商店、道具等对象。而ShoppingService主要负责处理异步收到请求,将处理结果返回给客户端。如果需要,分布式的事务也会在这层消化掉。至于逻辑,只是简单的调用领域服务Shopping::buyItem()。

    经过这次整理,感觉总体的思路清晰了很多。但仍还有一些困惑。如果player.receiveItem(),player.pay()不是在同一台服务器上处理怎么办,也就是任何逻辑服务器如果需要影响player的数据,都必须统一通过专门的一台服务器。这时候问题就来了,只要需要访问到别的服务器,那么就有异步操作。也就是要在Shopping类中用到异步通讯,这又违背了一开始我希望领域层不关心异步通讯的期望。如果上提到ShoppingService,似乎是可以的,但这一来又犯糊涂了。到底什么时候要放在ShoppingService,什么时候要放在Shoping?既然想让领域层不关心异步,那么领域层就应该按原本的思路去设计,自然而然会将player.pay()和player.receiveItem()放在shop.buyItem()中。

    如何是好呢???于是我问了一个没有研究过DDD的朋友,关于领域建模的概念,他也只是从我这里听到一些概念。他说,领域建模只是一种分析模型,和最终的设计模型之间本就是不同的,也就是说不管异步不异步,领域建模是不会变的。但设计模型肯定要关心异步还是同步。他这样说,似乎也有道理。但是Eric Evans指出的的Domain层难道不是最终的设计模型中的一部分吗?难道异步还是同步,一定要影响到所有逻辑的编写,而没办法在某一层消化掉吗?

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值