angularjs - 如何做正确的存储库工厂?

标签 angularjs typescript

我在项目之间有一些空闲时间,所以我决定学习 typescript。 因此我想做一个存储库工厂。这个想法很简单,有一些 API 我可以在其中访问 models crud 操作。拥有一个用于商业模型的 generic repository 是很好的解决方案。但仍然从 CRUD 方法中获取 model 类。

正确的做法是什么?有人可以帮我解决这个问题吗?如何正确执行?

我想要实现的是:

var factory = new RepositoryFactory($resource, 'http://api.com');
var repo = factory.getRepository(User);
var user = repo.getAll();

我开始做这样的事情:

IEntity:

'use strict';

export interface IEntity {
    id: number;
}

IRepository:

'use strict';

import {IEntity} from "./IEntity";

export interface IRepository<T extends IEntity> {
    getAll(params:Object): T[];
    getById(id:number): T;
    create(data:Object): T;
    update(id:number, data:{id:number}): T;
    remove(id:number): boolean;
}

RepositoryFactory

'use strict';

import {IEntity} from "./IEntity";
import {Repository} from "./Repository";

export default class RepositoryFactory {
    protected $resource:any;
    protected url:string;

    constructor($resource:any, url:string) {
        this.$resource = $resource;
        this.url = url;
    }

    public getRepository<T extends IEntity>(model:T):Repository {
        return new Repository(this.$resource, this.url, model)
    }
}

`Repository`:
'use strict';

import {IRepository} from "./IRepository";
import {IEntity} from "./IEntity";

export default class Repository<T extends IEntity> implements IRepository<T> {
    protected $resource:any;
    protected resource:any;
    protected url:string;
    protected model:T;

    constructor($resource:any, url:string, model:T) {
        this.$resource = $resource;
        this.url = url;
        this.model = model;
        this.resource = this.getResource(model.path);
    }

    getAll(params:Object):T[] {
        let results = this.resource.query((typeof params === 'undefined' ? {} : params), this.onSuccess);

        return this.returnPromise(results);
    }

    getById(id:number):T {
        let model = this.resource.get({id: id}, this.onSuccess);

        return this.returnPromise(model);
    }

    create(data:Object):T {
        let model = new this.resource(data);

        return model.$save().then(this.onSuccess);
    }

    update(id:number, data:Object):T {
        data.id = id;
        var model = new this.resource(data);

        return model.$update().then(this.onSuccess);
    }

    remove(id:number):boolean {
        var data = {id: id};
        var model = new this.resource(data);

        return model.$delete().then(this.onSuccess);
    }

    protected getResource(path:string) {
        return this.$resource(this.url + path, {id: '@id'}, {
            'update': {
                method: 'PUT'
            },
            'get': {
                method: 'GET'
            },
            'save': {
                method: 'POST'
            },
            'query': {
                method: 'GET'
            },
            'remove': {
                method: 'DELETE'
            },
            'delete': {
                method: 'DELETE'
            }
        });
    }

    protected onSuccess(response:any) {
        if (this.checkPropertyExistence(response, 'data')) {
            if (response.data instanceof Array) {
                let results = response.data;
                for (var key in results) {
                    if (results.hasOwnProperty(key)) {
                        results[key] = new this.model(results[key]);
                    }
                }

                return results;
            } else {
                return new this.model(response.data);
            }
        }

        return response;
    }

    protected transformRequest(obj:Object) {
        var str = [];
        for (var p in obj) {
            if (obj.hasOwnProperty(p)) {
                str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
            }
        }

        return str.join("&");
    }

    protected returnPromise(object:Object) {
        return object.$promise.then(function (result) {
            return result;
        });
    }

    protected checkPropertyExistence(obj:Object, paths:string|string[]) {
        for (var i = 0; i < paths.length; i++) {
            if (!obj || !obj.hasOwnProperty(paths[i])) {
                return false;
            }
            obj = obj[paths[i]];
        }
        return true;
    }
}

用户:

'use strict';

import {IEntity} from "./IEntity";

export default class User implements IEntity {
    id:number;
    name:string;

    static _path:string = '/users';

    constructor(id:number, name:string) {
        this.id = id;
        this.name = name;
    }

    static get path():string {
        return this._path;
    }
}

最佳答案

嘿伙计们,我设法为你们创建了工作示例。 该示例展示了如何使用 typescript 创建存储库工厂。

我准备了这个DEMO FIDDLE点击右侧的RUN,会出现单按钮页面。单击按钮后 console.log 将显示 getAll 方法 results

在示例中,我模拟了数据,只是为了表明工厂正常工作。如果有人想改进它,请随意并欢迎这样做!

它是如何工作的?

//create factory, you can do it in an abstract controller class
//and later extends controller by it so you can easy get access to repository
var factory = new RepositoryFactory();
//inject path for $resource (unused in example)
//and your model.entity namespace
var repo = factory.getRepository('/users', 'User');

//call repo method
var users = repo.getAll({});

当使用 Angular 时,创建 RepositoryFactory 作为 service。就这样。您可能还想注入(inject) $resource 以从 API 获取正确的数据。

这是一个完整的示例代码:

interface IEntity {
    id: number;
}

class Entity implements IEntity {
    private _id:number;
    private _name:string;
    private _birth:Date;

    constructor(parameters: {id:number, name:string, birth:Date}) {
        this._id = parameters.id;
        this._name = parameters.name;
        this._birth = parameters.birth;
    }

    get id():number {
        return this._id;
    }

    set id(value:number) {
        this._id = value;
    }

    get name():string {
        return this._name;
    }

    set name(value:string) {
        this._name = value;
    }

    get birth():Date {
        return this._birth;
    }

    set birth(value:Date) {
        this._birth = value;
    }
}

class RepositoryFactory {
    public getRepository<T extends IEntity>(path:string, model:string):IRepository<T> {
        return new Repository<T>(path, model)
    }
}

interface IRepository<T extends IEntity> {
    getAll(params:Object): T[];
    getById(id:number): T;
    create(data:Object): T;
    update(id:number, data:{id:number}): T;
    remove(id:number): boolean;
}

class Repository<T extends IEntity> implements IRepository<T> {
    protected path:string;
    protected model:string;

    constructor(path:string, model:string) {
        this.path = path;
        this.model = model;
    }

    getAll(params:Object):T[] {
        let results = [
            {id:1, name: 'rafal', birth:new Date()},
            {id:2, name: 'szymon', birth:new Date()},
            {id:3, name: 'mateusz', birth:new Date()},
        ];

        let entities= [];
        for (var key in results) {
            if (results.hasOwnProperty(key)) {
                let entity = Object.create(window[this.model].prototype);
                entity.constructor.apply(entity, new Array(results[key]));
                entities.push(entity);
            }
        }

        return entities;
    }

    getById(id:number):T {
        let object = {id:id, name: 'test', birth:new Date()};

        var entity = Object.create(window[this.model].prototype);
        entity.constructor.apply(entity, new Array(object));

        return entity;
    }

    create(data:Object):T {     
        var entity = Object.create(window[this.model].prototype);
        entity.constructor.apply(entity, new Array(data));

        return entity;
    }

    update(id:number, data:Object):T {
        var entity = Object.create(window[this.model].prototype);
        entity.constructor.apply(entity, new Array(data));

        return entity;
    }

    remove(id:number):boolean {
        return true;
    }
}

var factory = new RepositoryFactory();
var repo = factory.getRepository('/users', 'Entity');

var users = repo.getAll({});

关于angularjs - 如何做正确的存储库工厂?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35552942/

相关文章:

typescript - 重复/交替函数参数

mysql - Map.prototype.forEach 不遍历 Map

javascript - 如何修复 tsr-detect-possible-timing-attacks 潜在的定时攻击

angularjs - 应用程序中可重用的 AngularJS 服务

AngularJS Karma 测试 "Error: Unexpected request: GET"似乎没有执行请求

javascript - 错误 : [ng:areq] Argument 'GreetingController' is not a function, 未定义

typescript - 是否可以在 TypeScript 中定义 string.Empty?

reactjs - material-ui 对话框内的表单未在 Enter 上提交

ios - ionic 3 : WARNING: sanitizing unsafe URL value

css - 将 Angular Material 下拉菜单移至左侧