23

私は現在Rubyを学ぼうとしており、カプセル化とコントラクトの観点からRubyが提供するものについてもっと理解しようとしています。

C#では、インターフェイスを使用してコントラクトを定義できます。インターフェイスを実装するクラスは、定義された各メソッドとプロパティ(および場合によっては他のもの)の実装を提供することにより、コントラクト内の条件を満たさなければなりません。インターフェイスを実装する個々のクラスは、同じタイプの引数を受け入れ、同じタイプの結果を返す限り、コントラクトで定義されたメソッドのスコープ内で必要なことをすべて実行できます。

Rubyでこの種のことを強制する方法はありますか?

ありがとう

私がC#で意味することの簡単な例:

interface IConsole
{
    int MaxControllers {get;}
    void PlayGame(IGame game);
}

class Xbox360 : IConsole
{
   public int MaxControllers
   {
      get { return 4; }
   }

   public void PlayGame(IGame game)
   {
       InsertDisc(game);
       NavigateToMenuItem();
       Click();
   }
}

class NES : IConsole
{
    public int MaxControllers
    {
        get { return 2; }
    }

   public void PlayGame(IGame game)
   {
       InsertCartridge(game);
       TurnOn();
   }
}
4

6 に答える 6

25

rubyは動的型付け言語であるため、rubyにはインターフェースはありません。インターフェイスは基本的に、型の安全性を損なうことなく、さまざまなクラスを交換可能にするために使用されます。コードは、C#でIConsoleを実装するコンソールのように動作する限り、すべてのコンソールで機能します。「ダックタイピング」は、この種の問題に対処する動的言語の方法に追いつくために使用できるキーワードです。

さらに、コードの動作を検証するための単体テストを作成でき、作成する必要があります。すべてのオブジェクトには、respond_to?アサーションで使用できるメソッドがあります。

于 2010-08-17T18:10:28.037 に答える
14

Ruby には、他の言語と同じようにインターフェースがあります。

ユニットの責任、保証、およびプロトコルの抽象的な仕様であるInterfaceinterfaceの概念を、Java、C#、および VB.NET プログラミングのキーワードであるの概念と混同しないように注意する必要があります。言語。Ruby では、前者は常に使用されますが、後者は単に存在しません。

両者を区別することは非常に重要です。重要なのはInterfaceであり、 ではありませんinterface。は、interfaceほとんど役に立たないことを伝えます。メンバーをまったく持たないインターフェイスである Javaのマーカー インターフェイスほど、これをよく示しているものはjava.io.Serializableありませんjava.lang.Cloneable。これら 2 つの は非常に異なるinterface意味を持っていますが、まったく同じ署名を持っています。

では、異なる意味を持つ2 つinterfaceの s が同じ署名を持っている場合、偶数は正確interfaceに何を保証するのでしょうか?

別の良い例:

interface ICollection<T>: IEnumerable<T>, IEnumerable
{
    void Add(T item);
}

インターフェースSystem.Collections.Generic.ICollection<T>.Add何ですか?

  • コレクションの長さが減らないこと
  • 以前コレクションにあったすべてのアイテムがまだそこにあること
  • それitemはコレクションにある

そして、それらのどれが実際に表示されinterfaceますか? なし!メソッドが追加しなければならないinterfaceということは何もありません。コレクションから要素を削除することもできます。Add

これはその完全に有効な実装ですinterface:

class MyCollection<T>: ICollection<T>
{
    void Add(T item)
    {
        Remove(item);
    }
}

もう 1 つの例:それがsetjava.util.Set<E>であると実際に言っているのはどこでしょうか? どこにも!より正確には、ドキュメントで。英語で。

interfacesJava と .NET の両方のほとんどすべてのケースで、すべての関連情報は実際には型ではなくドキュメントにあります。では、とにかくタイプが興味深いことを何も教えてくれないのなら、なぜそれらを保持する必要があるのでしょうか? ドキュメントだけに固執しないのはなぜですか?それがまさに Ruby が行うことです。

インターフェイスを実際に意味のある方法で記述できる言語がにもあることに注意してください。ただし、これらの言語は通常、インターフェイスを記述する構成要素を呼び出さず、 " " と呼びます。依存型プログラミング言語では、たとえば、関数が元のコレクションと同じ長さのコレクションを返す、元のすべての要素が並べ替えられたコレクションにもある、それよりも大きな要素が前に現れない、というプロパティを表現できます。より小さな要素。interfacetypesort

要するに、Ruby には Java に相当するものはありませんinterfaceただし、 Java Interfaceに相当するものがあり、Javaのドキュメントとまったく同じです。

また、Java と同様に、Acceptance Testsを使用してInterfaceを指定することもできます。

特に、Ruby では、オブジェクトのインターフェイスは、何ができるclass、または何が混ざるかではなく、何ができるかによって決定されmoduleます。メソッドを持つ任意のオブジェクト<<に追加できます。これは、より複雑な の代わりにまたはArrayを単純に渡すことができる単体テストで非常に便利です。StringLoggerArrayLoggerinterface<<

別の例はStringIOで、これは と同じインターフェースを実装しているため、 のインターフェースIO大部分を実装していますが、 以外に共通の祖先を共有していません。FileObject

于 2010-08-17T22:23:41.550 に答える
5

インターフェースは通常、多重継承の欠如を補うために静的型付きオブジェクト指向言語に導入されます。言い換えれば、それ自体が有用なものというよりは、必要悪であるということです。

一方、ルビーは:

  1. 「ダックタイピング」による動的型付け言語であるため、2 つのオブジェクトでメソッドを呼び出したい場合、foo同じ祖先クラスを継承する必要も、同じインターフェースを実装する必要もありません。
  2. ミックスインの概念による複数の継承をサポートします。ここでもインターフェイスは必要ありません。
于 2010-08-17T19:41:54.103 に答える
4

Ruby には実際にはありません。インターフェイスとコントラクトは一般に、動的な世界ではなく、静的な世界に存在します。

本当に必要な場合は、非公式の契約を実装できるHandshakeというgem があります。

于 2010-08-17T18:11:51.583 に答える
0

Ruby はモジュールの概念をインターフェイスの代用 (一種) として使用します。Design Patterns in Ruby には、2 つの概念の違いと、Ruby がより柔軟なインターフェースを選択する理由について、非常に優れた例がたくさんあります。

http://www.amazon.com/Design-Patterns-Ruby-Russ-Olsen/dp/0321490452

于 2010-08-17T18:34:02.610 に答える
0

Jorg には良い点があります。Ruby にはインターフェイスがありますが、キーワードはありません。いくつかの返信を読んで、これは動的言語のマイナスだと思います。言語を介してインターフェイスを強制する代わりに、実装されていないメソッドをコンパイラでキャッチする代わりに、単体テストを作成する必要があります。また、オブジェクトを呼び出そうとしているときにオブジェクトが何であるかを突き止める必要があるため、メソッドを理解するのが難しくなります。

例として挙げます:

def my_func(options)
  ...
end

関数を見ても、単体テストや関数が呼び出される他の場所を探したり、メソッドを調べたりしなければ、オプションとは何か、関数が呼び出すメソッドやプロパティはわかりません。さらに悪いことに、メソッドはこれらのオプションを使用することすらできず、他のメソッドに渡します。これがコンパイラによってキャッチされるべきであるのに、なぜ単体テストを書くのか。問題は、動的言語でこの欠点を表現するには、別の方法でコードを記述しなければならないことです。

ただし、これには利点が 1 つあります。それは、動的プログラミング言語はコードを書くのが速いということです。インターフェイス宣言を記述する必要はなく、後でインターフェイスにアクセスして公開することなく、新しいメソッドとパラメーターを作成できます。トレードオフは、メンテナンスの速度です。

于 2016-05-30T03:49:30.177 に答える