贫血模型和充血模型对于接触后端的人说可能更熟悉

贫血模型

先画一张图

贫血模型

这张图展现的就是表现层常用的逻辑,即查询逻辑。而且是一个贫血模型

我们有一个User对象,伪代码如下

1
2
3
4
5
6
7
8
public class User
{
public string Name {get;set;}
public int Age {get;set;}
public string Id {get;set;}
public string NickName {get;set;}
public float Weight {get;set;}
}

总共有五个属性,但是在表现层的界面中,只需要显示三个属性:姓名、年龄、ID

我们在表现层使用GetUserById返回的是一整个User对象,这种数据流向模型叫做贫血模型

IUserModel的伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface IUserModel : IModel
{
User GetUserBuId(string id);
}
public class UserModel : AbstractModel,IUserModel
{
List<User> mUsers = new List<User>();
protected override void OnInit()
{
//...
}
public User GetUserById(string id){
return mUsers.FirstOrDefault(u =>u.Id == id);
}
}

我们可以看到Model中GetUserById返回的是User,最后显示的时候需要在表现层进行一层筛选

充血模型

也是一张图

充血模型

我们不返回完整的User了,而是定义一个新的UserInfo用来返回信息,这些信息和表现层UserInfoViewController一一对应

这个就是典型的充血模型

UserInfo伪代码

1
2
3
4
5
6
public class UserInfo
{
public string Name {get;set;}
public int Age {get;set;}
public string Id {get;set;}
}

IUserModel伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface IUserModel : IModel
{
UserInfo GetUserBuId(string id);//
}
public class UserModel : AbstractModel,IUserModel
{
List<User> mUsers = new List<User>();
protected override void OnInit()
{
//...
}
public UserInfo GetUserById(string id)//
{
return mUsers.Where(u => u.Id == id).Select(u => new UserInfo(){
Name = u.Name,
Age = u.Age,
Id = u.Id
}).FirstOrDefault();
}
}

充血模型就是表现层需要哪些数据,就刚好返回哪些数据,不多不少。

充血模型比贫血模型多做了一些工作,并且也多了一些性能消耗。

但是在越大型的项目中充血模型的好处就越明显。

因为充血模型,可以让我们的代码更精确地描述业务,会提高代码的可读性,比如表现层需要展示的是UserInfo,那么就返回UserInfo对象,而不是所有的表现层都直接获取User而分不开各个表现层要的是什么。贫血模型,会让我们的数据趋于混乱。

Framwork基于充血模型的查询建议

在Model内部直接给出查询方法

在Model内部直接给出查询方法

引人IUserInfoSystem

引入IUserInfoSystem用于封装IUserModel的查询

引人IUserInfoSystem

UserModel该返回User就返回User,而表现层需要的UserInfo需要在UserInfoSystem里过滤出来

这种方式其实是更标准一些的,很多服务器的四层架构都是这么实现的,这里的系统层也即是服务器端的应用层

使用Command加事件

使用Command加事件

在Command内部获取UserModel,并调用GetUserById,并且在Command内部将User转化为UserInfo,发送GetUserInfoByIdSucceedEvent(UserInfo userinfo)事件,我们在表现层监听此事件即可。

建议使用第二种、第三种查询方式,因为在很多情况下,数据所设计的Model不只有一个,很多需要组合查询,使用Command或者定义一个专门用来查询的System就能更好地访问多个Model,分层就是为了减少表现层的代码量。

充血模型是指在项目中流通的对象,不是在Model中定义的用于存储的对象(上述例子中User属于存储对象,UserInfo属于流通对象)流通。充血模型则是存储对象在流通。

查询是充血模型的主要用例之一,其他还有传参等也是需要充血模型的理念