2016-10-14 6 views
1

私は外部APIを使用してデータを表示しています。要約外部API

柔軟性を持たせるため、私はAPIを自分のコードから完全に切り離したいと思っています。自分で定義したデータ構造を使いたいと思っています。ここで

簡単にグラフィカルな概要: enter image description here

ここに例をタスクもう少しconcretを作るために:

はのデータが人々についてであると仮定しましょう:

API v1.0のは{"name": "John"}を吐きますAPI v1.1は{"pName": "John"}を吐き出します。 (APIレスポンスを解析し)、パーサー用とデータ自体の構造などのために1:

interface IPersonDataStructure { 
    name : string; 
} 

interface IPersonDataParser { 
    parse(input: string) : IPersonDataStructure; 
} 
このマイナーチェンジは私が内部的に二つのインターフェースを持っていたい私のコードを壊すことを防止するために

// This class uses any parser which implements IPersonDataParser 
// And uses IPersonDataStructure 
class Person { 

} 

そして、私はこだわっているところです:

は、それから私は、データ構造とパーサを組み合わせたクラスを持つようにしたいです!私は一緒に2つを組み合わせる方法を知らない!

私は人のインスタンスごとに、インスタンスのアイデア好きではない:パーサは(例えば関数のように)ステートレスである必要がありますので

let aPerson = new Person(new Parser(data)) 

を。

class Parser implements IPersonDataParser { 
    static public function parse(data : string) : IPersonDataStructure { 
     return {...} 
    } 
} 

class Person { 
    private _data : IPersonDataStructure; 

    constructor(data : string, parser : IPersonDataParser) { 
     this._data = parser.parse(data) 
    } 
} 

コールバックはオプションですが、私は彼らの署名を検証することができた場合にのみ:。

問題は活字体は私がクラスであることを行うことができなかったです

たとえば、これは正しく検証しません。この問題を解決する方法について

type PersonDataParser = (data : string) => IPersonDataStructure; 

// Whoops.. argument is missing! 
let aParser =() => { 
    return {...} 
} 

let aPerson = new Person('data', aParser) 

任意の提案ですか?

+0

あなたはここで取り組もうとしている問題は何ですか? – toskv

+0

説明済みの機能をクリーンな方法で実装したい – d3L

+0

これは実際にはstackoverflowの問題の種類ではありません。多分、コードレビュースタック交換のウェブサイトを試してみてください。ここでは、多くの意見に基づくソリューションを生成する予定です。 :) – toskv

答えて

1

まず、あなたは静的なメソッドを持っており、それがインターフェイスを満たすことができます - すべての型推論と構造タイプを使用して、次のように:

interface IPersonDataStructure { 
    name : string; 
} 

interface IPersonDataParser { 
    parse(input: string) : IPersonDataStructure; 
} 

class Parser { 
    public static parse(data : string) : IPersonDataStructure { 
     return { name: 'Steve' }; 
    } 
} 

class Person { 
    private _data : IPersonDataStructure; 

    constructor(data : string, parser : IPersonDataParser) { 
     this._data = parser.parse(data) 
    } 
} 

let person = new Person('', Parser); 

私はおそらくPersonはただ人を表すデザインを好みます構築するためにマッパーを取る必要はありませんでした。このようにもっと...

interface IPersonDataStructure { 
    name : string; 
} 

class Person { 
    constructor(private data : IPersonDataStructure) { 
    } 
} 

class PersonMapper { 
    public static map(data: string): Person { 
     return new Person({ 
      name: 'Steve' 
     }); 
    } 
} 

let person = PersonMapper.map('...'); 

バージョン番号がデータの一部である場合は、それを使って正しいマッピングを判断できます。

1

APIから返された2つのプロパティのどちらをチェックするアダプタを作成してみませんか?

interface ApiResponse { 
    name?: string; 
    pName?: string; 
} 

class Person { 
    public name: string; 

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

class ApiResponseAdapter { 
    private getName(response: ApiResponse): string { 
     if (response.pName) return pName; 
     if (response.name) return name; 

     // if neither are set, return null 
     return null; 
    } 

    public adapt(response: ApiResponse): Person { 
     let name = this.getName(response); 

     if (name === null) { 
      throw new Error("Invalid name for response: " + JSON.stringify(response)); 
     } 

     return new Person(name); 
    } 
} 

代わりにあなたが行動を処理するために実装を持っているベースApiResponseインターフェイスかもしれない:

interface ApiResponse { 
    name: string; 
} 

class Api_V1_0_Response implements ApiResponse { 
    public name: string; 

    constructor (json: any) { 
     this.name = json["name"]; 
    } 
} 

class Api_V1_1_Response implements ApiResponse { 
    public name: string; 

    constructor (json: any) { 
     this.name = json["pName"]; 
    } 
} 

class Person { 
    public name: string; 

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

class ApiResponseAdapter { 
    public adapt(response: ApiResponse): Person { 
     return new Person(
      response.name 
     ); 
    } 
} 

あるいはさらに一歩進み、他の二つによって拡張される抽象クラスBaseApiResponseあります

interface ApiResponse { 
    name: string; 
} 

abstract class BaseApiResponse implements ApiResponse { 
    public name: string; 

    constructor (nameKey: string, json: any) { 
     this.name = json[nameKey]; 
    } 
} 

class Api_V1_0_Response extends BaseApiResponse { 
    constructor (json: any) { 
     super("name", json); 
    } 
} 

class Api_V1_1_Response extends BaseApiResponse { 
    constructor (json: any) { 
     super("pName", json); 
    } 
} 

class Person { 
    public name: string; 

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

class ApiResponseAdapter { 
    public adapt(response: ApiResponse): Person { 
     return new Person(
      response.name 
     ); 
    } 
}