我正在开发一款适用于 iOS 的小型 2 人纸牌游戏应用程序。目前,我已将此应用程序分为 3 个模块。
- 用户界面
- 游戏逻辑
- 联网
我在网络模块中有两个公共协议:
public protocol ConnectionManager {
init(name: String)
var peers: Property<[String]> { get }
func invitePeer(at index: Int)
func respond(accept: Bool)
var invitation: Signal<String, NoError> { get }
var response: Signal<Bool, NoError> { get }
}
public protocol MessageTransmission {
func send(_ data: Data)
var data: Signal<Data, NoError> { get }
}
实际上只有一个具体的实现同时符合这两种协议。让我们说:
class Foo: ConnectionManager, MessageTransmission {
// ... codes omitted
}
UI模块从用户那里接收一个名称并使用它来初始化一个Foo
. 然后根据peers
属性显示附近的玩家。当用户提交开始新游戏的邀请时,UI模块将此请求转发给ConnectionManager
并ConnectionManager
处理那些肮脏的工作。
对于游戏逻辑模块,它只关心消息传输,但传输依赖于前面的“邀请-响应”步骤,因为我们需要一个目标来与之交换消息。(目标相关概念被封装,所以游戏逻辑只知道有一个东西可以发送消息和接收消息。)
我的想法是:一旦建立了会话,即一旦用 响应邀请true
,UI模块就会初始化一个游戏逻辑事物(可能是一个 type 的实例Game
)并通过ConnectionManager
(虽然UI模块初始化一个 type 的实例Foo
,它存储类型为ConnectionManager
) 的实例。但问题是,即使它们在内部由单一类型实现,ConnectionManager
也与从外部看时无关。MessageTransmission
- 我可以在任一侧做一个强制案例,但它看起来很棘手。
- 我可以将这两个协议结合起来,但是UI模块和游戏逻辑模块与多余的接口(具有比需要更多功能的接口)交互。
我应该走哪条路?还是有更好的方法来做到这一点?
ps:Foo
只能由UI模块初始化,因为它是唯一知道name
. 并且还需要将相同的实例传递给游戏逻辑模块,因为有一些内部状态(目标相关的东西)在之前与UI模块的交互中被修改,并影响到以后与游戏逻辑模块的交互。我想不出另一种方法来做到这一点。