web-dev-qa-db-ja.com

流APIなAPIを作成する

どうすれば自然に流createなAPIを作成できますか?

これは主に拡張メソッドを使用していますか?

52
mrblah

この記事 は、私が今までできなかったよりもずっと良い説明です。

編集、コメントでこれを絞ることができません...

インターフェイスには、実装と使用方法の2つの側面があります。作成側で行うべき作業がさらにありますが、それには同意しますが、主な利点は物事の使用側にあります。実際、私にとって、流れるようなインターフェースの主な利点は、より自然で覚えやすく使いやすいことです。そして、多分、流APIな形でAPIを絞らなければならない努力は、より良いAPIを考え出すことにつながるのでしょうか?

Martin Fowlerが 流fluentなインターフェースに関するオリジナル記事 で述べているように:

おそらく、このスタイルで最も重要なことは、内部のDomainSpecificLanguageのラインに沿って何かをすることです。実際、これが、「流fluent」という用語を選択して説明した理由です。多くの点で、2つの用語は同義語です。 APIは主に、読みやすく、流れるように設計されています。この流encyさの代償は、思考とAPI構築自体の両方で、より多くの努力です。コンストラクター、セッター、および追加メソッドの単純なAPIは、作成がはるかに簡単です。 Nice Fluent APIを思い付くには、少し考えが必要です。

ほとんどの場合、APIは一度作成されて何度も使用されるため、追加の努力に値する場合があります。

そして冗長?プログラムの可読性に役立つ場合、私はすべて冗長です。

44
fvu

MrBlah、

拡張メソッドを記述して流fluentなインターフェイスを記述できますが、より良い方法はビルダーパターンを使用することです。私はあなたと同じ船に乗っており、流interfacesなインターフェイスのいくつかの高度な機能を理解しようとしています。

以下に、 別のスレッド で作成したサンプルコードを示します。

public class Coffee
{
    private bool _cream;
    private int _ounces;

    public static Coffee Make { get { return new Coffee(); } }

    public Coffee WithCream()
    {
        _cream = true;
        return this;
    }
    public Coffee WithOuncesToServe(int ounces)
    {
        _ounces = ounces;
        return this;
    }
}

var myMorningCoffee = Coffee.Make.WithCream().WithOuncesToServe(16);
35
sam

多くの人々は、Martin Fowlerが流fluentなAPI議論の顕著な指数であると述べていますが、彼の初期の設計主張は、実際には 流fluentなビルダーパターン または メソッドチェーン を中心に展開しています。 Fluent APIは、実際の 内部ドメイン固有言語 にさらに進化させることができます。文法のBNF表記を「流fluentなAPI」に手動で変換する方法を説明する記事は、次のとおりです。

http://blog.jooq.org/2012/01/05/the-Java-fluent-api-designer-crash-course/

この文法を変換します:

enter image description here

これにJava API:

// Initial interface, entry point of the DSL
interface Start {
  End singleWord();
  End parameterisedWord(String parameter);
  Intermediate1 Word1();
  Intermediate2 Word2();
  Intermediate3 Word3();
}

// Terminating interface, might also contain methods like execute();
interface End {
  void end();
}

// Intermediate DSL "step" extending the interface that is returned
// by optionalWord(), to make that method "optional"
interface Intermediate1 extends End {
  End optionalWord();
}

// Intermediate DSL "step" providing several choices (similar to Start)
interface Intermediate2 {
  End wordChoiceA();
  End wordChoiceB();
}

// Intermediate interface returning itself on Word3(), in order to allow
// for repetitions. Repetitions can be ended any time because this 
// interface extends End
interface Intermediate3 extends End {
  Intermediate3 Word3();
}

JavaとC#は多少似ていますが、この例は確かにユースケースにも変換されます。上記の手法は jOOQ で頻繁に使用されています。これは、JavaでSQL言語をモデル化する流APIなAPI /内部ドメイン固有言語です

19
Lukas Eder

これは非常に古い質問であり、この回答はおそらく回答ではなくコメントでなければなりませんが、議論を続ける価値のあるトピックだと思います。この回答はコメントには長すぎます。

「流encyさ」に関する当初の考え方は、コードを少しわかりやすくしながら、オブジェクトにパワーと柔軟性(メソッドチェーンなど)を追加することを基本的に考えていたようです。

例えば

Company a = new Company("Calamaz Holding Corp");
Person p = new Person("Clapper", 113, 24, "Frank");
Company c = new Company(a, 'Floridex', p, 1973);

より「流fluent」ではない

Company c = new Company().Set
    .Name("Floridex");
    .Manager(
        new Person().Set.FirstName("Frank").LastName("Clapper").Awards(24)
    )
    .YearFounded(1973)
    .ParentCompany(
        new Company().Set.Name("Calamaz Holding Corp")
    )
;

しかし、私にとっては、後者は、実際には、より強力でも柔軟でも、自明ではありません

Company c = new Company(){
   Name = "Floridex",
   Manager = new Person(){ FirstName="Frank", LastName="Clapper", Awards=24 },
   YearFounded = 1973,
   ParentCompany = new Company(){ Name="Calamaz Holding Corp." }
};

..実際、私はこの最後のバージョンを以前のものよりも作成、読み取り、および保守しやすいと呼びます。また、舞台裏の手荷物も大幅に少なくなります。私にとって重要なのは、(少なくとも)2つの理由です。

1-オブジェクトのレイヤーの作成と保守に関連するコスト(誰が関係なく)は、それらを消費するコードの作成と保守に関連するコストと同じくらい、現実的で関連性があり、重要です。

2-オブジェクトのレイヤーに埋め込まれたコードの肥大化は、それらのオブジェクトを消費するコードのコードの肥大化と同じ数の(それ以上ではないにしても)問題を引き起こします。

最後のバージョンを使用すると、1つの非常に単純なコード行を追加するだけで、Companyクラスに(潜在的に有用な)プロパティを追加できます。

だからと言って、メソッドチェーンを行う場所がないと感じているわけではありません。 (JavaScriptで)のようなことができるのが本当に好きです

var _this = this;
Ajax.Call({
    url: '/service/getproduct',
    parameters: {productId: productId},
)
.Done(
    function(product){
        _this.showProduct(product);
    }
)
.Fail(
    function(error){
        _this.presentError(error);
    }
);

..where(私が想像している仮想の場合)DoneとFailは、元のAjaxオブジェクトへの追加であり、元のAjaxオブジェクトコードや、元のAjaxオブジェクト、およびコードの一般的な組織に対する例外である一時的なものを作成することなく。

そのため、オブジェクトの関数のサブセットが「this」オブジェクトを返すようにすることで価値を見つけました。実際、他の方法でvoidを返す関数がある場合は常に、これを返すようにすることを検討します。

しかし、「流fluentなインターフェース」(例:「セット」)をオブジェクトに追加することにはまだ大きな価値がありませんが、理論的には、名前空間のようなコード編成が練習から生じる可能性があるようですそれは価値があるかもしれません。 (「セット」は特に価値はありませんが、「コマンド」、「クエリ」、および「転送」は、物事を整理し、追加および変更の影響を促進および最小化するのに役立つ場合があります。) 、それがどのように行われたかにもよりますが、コーダーの典型的な注意レベルの改善と保護レベルへの注意があります-その欠如は確かに大きな悲嘆を引き起こしました。

9
Shavais

キッス:シンプルにバカにしてください。

流designなデザインとは、API全体で使用される審美的なデザイン原則の1つです。 APIで使用する方法論はわずかに変更される可能性がありますが、一般的に一貫性を保つ方が良いでしょう。

「すべての異なるタイプの方法論を使用しているため、誰でもこのAPIを使用できる」と考えるかもしれません。真実は、APIの構造/データ構造を新しい設計原則または命名規則に一貫して変更しているため、ユーザーが失われたと感じ始めることです。

途中で別の設計原則に変更したい場合。たとえば、いくつかの高い命令能力のためにエラーコードから例外処理に変換します。それは愚かであり、通常、尾の痛みがたくさんあります。コースを継続し、顧客が使用および販売できる機能を追加する方が、顧客にすべての問題を書き直して再発見させるよりも優れています。

上記からわかるように、Fluent APIを作成する作業には、見た目以上のものがあることがわかります。文章を書き始める前に行うべき心理的、美的選択がありますが、それでも顧客の需要に適合し、一貫性を保つという気持ち、必要性、欲求が最も困難です。

6
Chad

流れるようなAPIとは

ウィキペディアはここでそれらを定義します http://en.wikipedia.org/wiki/Fluent_interface

流なインターフェースを使用しない理由

従来の流interfaceなインターフェイスを実装しないことをお勧めします。これにより、記述する必要があるコードの量が増え、コードが複雑になり、不要な定型文が追加されるだけです。

別のオプション、何もしない!

何も実装しないでください。プロパティを設定するための「簡単な」コンストラクタを提供しないでください。また、クライアントを支援するための巧妙なインターフェイスを提供しないでください。クライアントが通常どおりにプロパティを設定できるようにします。 .Net C#またはVBでは、これは object initializers を使用するのと同じくらい簡単です。

Car myCar = new Car { Name = "Chevrolet Corvette", Color = Color.Yellow };

したがって、コードに巧妙なインターフェイスを作成する必要はありません。これは非常に読みやすいものです。

設定する必要があるプロパティの非常に複雑なSetsがある場合、または特定の順序で設定する場合は、別の構成オブジェクトを使用し、別のプロパティを介してクラスに渡します。

CarConfig conf = new CarConfig { Color = Color.Yellow, Fabric = Fabric.Leather };
Car myCar = new Car { Config = conf };
5
badbod99

流fluentなAPIを書くのは複雑です。だから Diezel はJava用のFluent APIジェネレーターです。以下に対するインターフェース(またはコース)を備えたAPIを生成します。

  1. 呼び出しフローを制御する
  2. ジェネリック型(guice oneなど)をキャッチする

実装も生成します。

Mavenプラグインです。

1
eric

流れるようなAPIの場合:

myCar.SetColor(Color.Blue).SetName("Aston Martin");

このビデオをご覧ください http://www.viddler.com/explore/dcazzulino/videos/8/

1

いいえ、はい。基本は、流interfaceに振る舞うタイプのインターフェースです。拡張メソッドを備えたライブラリは、この動作を拡張し、インターフェイスを返すことができます。拡張メソッドを使用すると、他のメソッドを使用して流APIなAPIを拡張できます。

優れた流fluentな設計は難しく、基本的な構成要素を完全に微調整するためにかなり長い試行錯誤の期間がかかります。構成またはセットアップ用の流fluentなAPIはそれほど難しくありません。

流なAPIの構築を学習するには、既存のAPIを調べます。 FluentNHibernateをFluent .NET APIまたはICriteriaのFluentインターフェイスと比較します。多くの構成APIも「流fluentに」設計されています。

0
Abel