构建 models/collections/classes 时我应该怎么想?

How should I think when building models/collections/classes?

整个周末,我一直在反复考虑在构建模型和 类 我的项目时应该如何思考,但我无法全神贯注。

我会尽力解释(如果我需要进一步解释请发表评论),我有一个遥控器 api,我可以在其中选择一些列表,这些列表将显示在一个应用程序。 API 的响应在 JSON 中,我在一个包含列表对象的简单数组结构中获取列表。

这是我获取列表的 RemoteService 提供商的一小段摘录:

export class RemoteService<Type> {
  public resource: string;
  private actionUrl: string;
  private headers: Headers;

  constructor(private _http: Http) {
      this.actionUrl = 'API_URL';

      this.headers = new Headers();
      this.headers.append('Content-Type', 'application/json');
      this.headers.append('Accept', 'application/json');
  }

  public GetAll = (): Observable<Type[]> => {
    return this._http.get(this.actionUrl + this.resource)
      .map((response: Response) => <Type[]>response.json())
      .catch(this.handleError);
  }
}

当我决定获取主页上的所有列表时,我将它们加载到页面控制器中的 Observable Array 中,然后在其中映射结果并将每个对象实例化为 ListModel .

export class HomePage {

  lists: Observable<Array<ListModel>>;
  listsObserver: any;

  constructor(public nav: NavController, public remoteService: RemoteService<ListModel>) {
    this.lists = Observable.create(observer => {
      this.listsObserver = observer;
    });

    this.remoteService.resource = 'lists';

    this.remoteService
      .GetAll()
      .subscribe((data:ListModel[]) => {
          this.listsObserver.next(data.map(list => new ListModel(list.lid, list.title, list.items)));
        },
        error => console.log(error),
        () => console.log('Get all Items complete'));
  }
}

ListModel 如下所示:

export class ListModel {

  constructor(public lid: number, public title: string, public items: any[]) {
    this.lid = lid;
    this.items = items;
  }
}

做完所有这些之后,我开始怀疑自己这是否是个好方法。我想了解如何真正正确使用 angular 2..

最后是我的问题:

首先,我应该在 ListModel 中创建观察者,而不是在我想要显示或获取列表的每个页面中创建观察者吗?或者我应该为此创建一个单独的 ListCollection 然后在我需要的地方加载它吗?如果不是后者,那我该怎么想?

然后另一个额外的问题,是否可以根据我加载它的位置将加载的对象从 RemoteService 转换为动态模型? I read the top comment here 并得出结论,应该有办法做到这一点,对吗?

此致,

Jake the Snake(不是摔跤手)

从您发布的代码来看,您大体上似乎是在正确的轨道上!让我们看看一些细节。

RemoteService

中创建真实的 class 个实例

目前,RemoteService 转换为该类型,但不会实例化该类型的真实对象。如果你想实现一个通用的解决方案,你应该使用factory pattern(为了简洁省略细节):

export interface TypeFactory<Type> {
    public create(data:any):Type;
}
export class RemoteService<Type> {
  constructor(private _http: Http, private factory:TypeFactory<Type>) {
      // ...
  }

  public GetAll(): Observable<Type[]> => {
    return this._http.get(this.actionUrl + this.resource)
        .map((response: Response) => response.json())
        .map((data:any) => {
            // Now `data` should be an array of the expected type, depending on the server side.
            // So we need to pass each element to the factory to create an actual instance.
            // We will then return the array of instances to be emitted to the observable with the correct type.
            return data.items.map((item:any) => this.factory.create(data));
        })
        .catch(this.handleError);
  }
}

现在 GetAll() observable 确实会发出 Type 个实例,前提是工厂完成了它的工作。

定义一个TypeFactory

TypeFactory 的工作是将任意对象变成具体的 class 实例。那么让我们看看 ListModel:

会是什么样子
export class ListModelFactory implements TypeFactory<ListModel> {
    public create(data:any):ListModel {
        // todo: validate data
        return new ListModel(data.lid, data.title, data.items);
    }
}

连接组件中的部件

现在你可以连接两个部分来实现你想要的(我只是假设你的HomePage实际上是一个@Component):

@Component(...)
export class HomePage implements OnInit {

    lists: Array<ListModel>;

    constructor(public nav: NavController, public remoteService: RemoteService<ListModel>) {
    }

    ngOnInit() {
        this.remoteService
            .GetAll()
            .subscribe(
                (data:ListModel[]) => this.lists = data,
                error => console.log(error),
                () => console.log('Get all Items complete')
            );
    }
}

在您看来,您现在可以访问 lists 属性 以在 observable 解析了一个值后输出您的数据。使用 AsyncPipe 你可以进一步简化你的组件。

实际工厂隐藏在RemoteService<ListModel>中,需要injected using DI


更新: 实施 AsyncPipeHomeComponent 现在归结为:

@Component({
    template: `<div *ngFor="let listModel of lists | async"> ... {{listModel}} ...</div>`
})
export class HomePage implements OnInit {

    lists: Observable<Array<ListModel>>;

    constructor(public nav: NavController, public remoteService: RemoteService<ListModel>) {
    }

    ngOnInit() {
        this.lists = this.remoteService.GetAll();
    }
}