﻿# 10. 架构规范 与 推荐用法

QFramework 架构提供了四个层级：
* 表现层：IController
* 系统层：ISystem
* 数据层：IModel
* 工具层：IUtility


除了四个层级，还提供了 Command、Query、Event、BindableProperty 等概念和工具。

这里有一套层级的规则，如下：

* 表现层：ViewController 层。IController接口，负责接收输入和状态变化时的表现，一般情况下，MonoBehaviour 均为表现层
  * 可以获取 System、Model
  * 可以发送 Command、Query
  * 可以监听 Event

Controller 的接口定义如下：

```csharp
#region Controller

public interface IController : IBelongToArchitecture, ICanSendCommand, ICanGetSystem, ICanGetModel,ICanRegisterEvent, ICanSendQuery
{
}

#endregion
```

* 系统层：System层。ISystem接口，帮助IController承担一部分逻辑，在多个表现层共享的逻辑，比如计时系统、商城系统、成就系统等
  * 可以获取 System、Model
  * 可以监听Event
  *  可以发送Event

System 的接口定义如下：

```csharp
#region System

public interface ISystem : IBelongToArchitecture, ICanSetArchitecture, ICanGetModel, ICanGetUtility,ICanRegisterEvent, ICanSendEvent, ICanGetSystem
{
    void Init();
}
```


* 数据层：Model层。IModel接口，负责数据的定义、数据的增删查改方法的提供
  * 可以获取 Utility
  * 可以发送 Event


Model 的接口定义如下：
```csharp
public interface IModel : IBelongToArchitecture, ICanSetArchitecture, ICanGetUtility, ICanSendEvent
{
    void Init();
}
```


* 工具层：Utility层。IUtility接口，负责提供基础设施，比如存储方法、序列化方法、网络连接方法、蓝牙方法、SDK、框架继承等。啥都干不了，可以集成第三方库，或者封装API

Utility 的接口定义如下:
```csharp
#region Utility

public interface IUtility
{
}

#endregion
```


* Command：命令，负责数据的增删改。
  * 可以获取 System、Model
  * 可以发送 Event、Command

Command 的接口定义如下：

```csharp
public interface ICommand : IBelongToArchitecture, ICanSetArchitecture, ICanGetSystem, ICanGetModel, ICanGetUtility,ICanSendEvent, ICanSendCommand, ICanSendQuery
{
    void Execute();
}
```

* Query：查询、负责数据的查询
  * 可以获取 System、Model
  * 可以发送 Query

```csharp
public interface IQuery<TResult> : IBelongToArchitecture, ICanSetArchitecture, ICanGetModel, ICanGetSystem,ICanSendQuery
{
    TResult Do();
}
```


* 通用规则：
  - IController 更改 ISystem、IModel 的状态必须用Command
  - ISystem、IModel 状态发生变更后通知 IController 必须用事件或BindableProperty
  - IController可以获取ISystem、IModel对象来进行数据查询
  - ICommand、IQuery 不能有状态,
  - 上层可以直接获取下层，下层不能获取上层对象
  - 下层向上层通信用事件
  - 上层向下层通信用方法调用（只是做查询，状态变更用 Command），IController 的交互逻辑为特别情况，只能用 Command

通用规则是理想状态下的一套规则，但是落实的实际项目，很有可能需要对以上规则做一些修改。

修改的方式非常简单，比如我希望 IController 可以发送事件，那么我们只需要在 IController 接口上增加一个 ICanSendEvent 接口即可，代码如下:

```csharp
    #region Controller

    public interface IController : IBelongToArchitecture, ICanSendCommand, ICanGetSystem, ICanGetModel,
        ICanRegisterEvent, ICanSendQuery,
        ICanSendEvent // +
    {
    }

    #endregion
```

这样，就可以在 Controller 对象里，通过 this.SendEvent 来发送事件了。

如果是打算先了解或学习 QFramework 架构，那么我推荐就先按照 QFramework 默认的架构规范来做练习项目。

如果是打算马上用 QFramework 做项目，那么可以再保持原有开发习惯的基础上，一点点引入 QFramework 的概念，比如一开始用 BindableProperty 和 Architecture 来解决 Model 和数据更新的问题。

再慢慢开始用 Command 来解决交互逻辑臃肿的问题，以此类推，直到能完全掌握全部概念，最终能修改和定制 QFramework.cs 源码。

## 更多内容

*   转载请注明地址：[liangxiegame.com](https://liangxiegame.com) （首发） 微信公众号：凉鞋的笔记
*   QFramework 主页：[qframework.cn](https://qframework.cn)
*   QFramework 交流群: 623597263
*   QFramework Github 地址: [https://github.com/liangxiegame/qframework](https://github.com/liangxiegame/qframework)
*   QFramework Gitee 地址：[https://gitee.com/liangxiegame/QFramework](https://gitee.com/liangxiegame/QFramework)
*   GamePix 独立游戏学院 & Unity 进阶小班地址：[https://www.gamepixedu.com/](https://www.gamepixedu.com/)