5

问题

我有一个具有User对象和Student对象的应用程序。一些用户是学生。所有学生都是用户。在数据库(基于 django-ORM)中,这表示为一个Student表,该表具有该表的外键User

我正在尝试在 iOS 应用程序中创建一个 REST API 和一个对象层次结构来模拟这个 API。我在决定如何建模时遇到了麻烦。

当前的解决方案

我想出的最好的方法是:User在 iOS 中有一个模型,在 iOS 中有一个Student模型,它继承自User并使用更多属性扩展它。然后,有一个方法从服务器接收 JSON 响应,并根据字典创建一个User一个模型。Student

最后,服务器需要始终给我最具体的类型。即,当我登录到服务器时,它将决定我是学生还是普通用户,并将返回正确的字典。

这是最好的方法吗?

这听起来有点复杂。但是我想到的任何其他建模方式,例如改变数据库的布局方式,都会给我一个数据库不知道所有约束的设计。例如,Student允许对象拥有其他对象(例如,homework_paper)。我可以用一个User对象而不是对象的外键来建模它Student,并说它Student只是用户的扩展。homework_paper但是数据库并没有强制 a必须由学生拥有这一事实。

有没有更好的方法来解决我缺少的这个问题?

4

1 回答 1

2

There is nothing that says the classes in your UI layer need to match 1-on-1 with your domain classes. Just like your domain classes do not have to follow your database tables exactly.

You can think of the classes for your UI layer your UI representations as a different set of classes. Classes you needed to make your UI work, or needed to use a framework to your advantage without compromising the business rules in your domain model and/or database design.

Your User UI class could well be a class that wraps both user and student domain classes. It would have knowledge of both User and Student domain classes. It is then up to this wrapper class to instantiate either a User or Student.

Another approach would be to model the User-Student relation as a "has a" relation instead of a "is a". After all, what are you going to do when user's can not only be students but teachers as well. For example when a teacher enrolls in some other course than the one (s)he teaches. Usually, these kinds of relations are better modelled using Roles than as "is a" relations. See Martin Fowler for more info on Dealing with Roles.

In any case, the User UI class would be the basis for your representation in your REST implementation and fill extra parts in that representation dependent on whether it is dealing with a user or a student or - in the role based approach - a user that has student stuff associated with it:

{
  "user": "/users/1234",
  "name": "Some non student's name",
  "stats": {
    ...
  }
}, 
{
  "user": "/users/4567",
  "name": "Some Student's name",
  "stats": {
    ...
  }
  "papers": [
    { "paperid": "/users/papers/111"
      ...
    },
    { "paperid": "/users/papers/222"
      ...
    },
    { "paperid": "/users/papers/333"
      ...
    }
  ]
}

Edit in response to comments

The server has to decide that anyway at some level, unless you want to have your UI differentiate between users and students at the URI level. Which I recommend AGAINST. It makes for unusable UI's. The user isn't interested in the implementation details and doesn't want to be confronted with them.

But no, if's are not needed.

Use polymorfism to your advantage.

The server can put polymorfism to good use receiving a student instance from its data access framework for any user that it retrieves by id. Students after all can always be referenced as users. So the server can simply ignore the fact that the user reference it gets from the data access framework might be a student. When the server actually needs to do/add specific student stuff, it should do so in a derived class.

No if statement needs to be used anywhere for this. Not even in the UI classes. The UI just needs to know that the User reference it receives could also be a Student and act accordingly. Preferably not by if User is Student (that would be tying the UI way to deeply to the class hierarchy), but by if IUser implements IStudent: asking the User reference whether it also implements the Student interface, and then getting and using that IStudent interface reference.

于 2012-11-02T17:26:49.633 回答