1

我正在开发一款适用于 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模块将此请求转发给ConnectionManagerConnectionManager处理那些肮脏的工作。

对于游戏逻辑模块,它只关心消息传输,但传输依赖于前面的“邀请-响应”步骤,因为我们需要一个目标来与之交换消息。(目标相关概念被封装,所以游戏逻辑只知道有一个东西可以发送消息和接收消息。)

我的想法是:一旦建立了会话,即一旦用 响应邀请trueUI模块就会初始化一个游戏逻辑事物(可能是一个 type 的实例Game)并通过ConnectionManager(虽然UI模块初始化一个 type 的实例Foo,它存储类型为ConnectionManager) 的实例。但问题是,即使它们在内部由单一类型实现,ConnectionManager也与从外部看时无关。MessageTransmission

  • 我可以在任一侧做一个强制案例,但它看起来很棘手。
  • 我可以将这两个协议结合起来,但是UI模块和游戏逻辑模块与多余的接口(具有比需要更多功能的接口)交互。

我应该走哪条路?还是有更好的方法来做到这一点?

ps:Foo只能由UI模块初始化,因为它是唯一知道name. 并且还需要将相同的实例传递给游戏逻辑模块,因为有一些内部状态(目标相关的东西)在之前与UI模块的交互中被修改,并影响到以后与游戏逻辑模块的交互。我想不出另一种方法来做到这一点。

4

1 回答 1

0

正如我从您的解释中了解到的那样,您需要将MessageTransmition实现传递给游戏逻辑,但不想传递ConnectionManager

一旦MessageTransmission取决于您发出的邀请(或接受邀请)的结果,ConnectionManager您就需要MessageTransmition从内部构建符合的对象ConnectionManager并传递给游戏逻辑。是的,这意味着您将这两个实体结合在一起,但在这种情况下它们将承担明确的责任。

考虑这种协议:

protocol ConnectionManager {
  func respond(accept: Bool) -> Signal<MessageTransmition, Error>
}

respond()方法接受邀请并MessageTransmission在成功时构建符合要求的对象,如果接受失败或邀请被拒绝,则返回错误。您可以将此对象传递给游戏逻辑。

于 2017-07-18T11:15:58.810 回答