122 votes

Qu'est-ce que l'interface java équivalente en Ruby?

Pouvons-nous exposer les interfaces dans Ruby comme nous le faisons en Java et appliquer les modules ou les classes Ruby pour implémenter les méthodes définies par interface.

Une solution consiste à utiliser l'héritage et method_missing pour obtenir le même résultat, mais existe-t-il une autre approche plus appropriée?

89voto

Jared Beck Points 4975

Essayez les "exemples partagés" de rspec:

https://www.relishapp.com/rspec/rspec-core/v/3-0/docs/example-groups/shared-examples

Vous écrivez une spécification pour votre interface, puis vous mettez une ligne dans la spécification de chaque implémenteur, par exemple.

 it_behaves_like "my interface"
 

87voto

Jörg W Mittag Points 153275

Ruby a des Interfaces comme toute autre langue.

Notez que vous devez être prudent de ne pas confondre le concept de l' Interface, qui est un résumé de la spécification des responsabilités, de garanties et de protocoles d'une unité avec le concept de l' interface qui est un mot-clé dans le Java, C# et VB.NET les langages de programmation. En Ruby, nous utilisons l'ancien tout le temps, mais celle-ci n'existe tout simplement pas.

Il est très important de distinguer les deux. Ce qui est important, c'est l' Interface, pas le interface. L' interface vous dit presque rien d'utile. Rien ne montre mieux que le marqueur interfaces en Java, qui sont des interfaces qui n'ont pas de membres à tous: il suffit de prendre un coup d'oeil à l' java.io.Serializable et java.lang.Cloneable; ces deux - interfaces entend très différentes choses, mais ils ont encore le exactement la même signature.

Ainsi, si deux interfaces qui signifient des choses différentes, ont la même signature, ce qui exactement est l' interface même en vous garantissant?

Un autre bon exemple:

package java.util;

interface List<E> implements Collection<E>, Iterable<E> {
    void add(int index, E element)
        throws UnsupportedOperationException, ClassCastException,
            NullPointerException, IllegalArgumentException,
            IndexOutOfBoundsException;
}

Qu'est-ce que l' Interface de l' java.util.List<E>.add?

  • que la longueur de la collection ne diminue pas
  • que tous les éléments qui étaient dans la collection avant sont toujours là
  • qu' element est dans la collection

Et celles qui s'affiche en fait dans l' interface? Aucun! Il n'y a rien dans l' interface qui dit que l' Add méthode doit encore ajouter à tout, il peut tout aussi bien supprimer un élément de la collection.

C'est parfaitement valide la mise en œuvre de l' interface:

class MyCollection<E> implements java.util.List<E> {
    void add(int index, E element)
        throws UnsupportedOperationException, ClassCastException,
            NullPointerException, IllegalArgumentException,
            IndexOutOfBoundsException {
        remove(element);
    }
}

Un autre exemple: où en java.util.Set<E> est-ce vraiment dire que c'est, vous le savez, un jeu? Nulle part! Ou plus précisément, dans la documentation. En Anglais.

Dans presque tous les cas d' interfaces, à la fois à partir de Java et de .NET, tous les pertinentes de l'information est en fait dans les docs, pas dans les types de. Donc, si les types ne peux pas te dire quelque chose d'intéressant, de toute façon, pourquoi les garder? Pourquoi ne pas coller juste pour la documentation? Et c'est exactement ce que Ruby n'.

Notez qu'il existe d'autres langues dans lesquelles l' Interface peut effectivement être décrit d'une manière significative. Cependant, ces langues n'est généralement pas appel de la construction qui décrit l' Interface "interface", ils l'appellent type. Dans un dépendante de type de langage de programmation, vous pouvez, par exemple, exprimer les propriétés que l' sort fonction retourne une collection de la même longueur que l'original, que chaque élément qui est à l'origine, est également dans la collection triée et qu'aucun grand élément apparaît avant un plus petit élément.

Donc, en résumé: Ruby n'a pas d'équivalent à un Java interface. Il n'a cependant un équivalent Java de l'Interface, et son exactement les mêmes que dans Java: la documentation.

Aussi, tout comme en Java, Tests d'Acceptation peut être utilisé pour spécifier *Interface*s ainsi.

En particulier, dans le Rubis, l' Interface d'un objet est déterminée par ce qu'il peut faire, pas ce que l' class est est ou ce qu' module il se mélange. Tout objet qui a un << méthode peut être ajouté. Ceci est très utile dans les tests unitaires, où vous pouvez simplement passer un Array ou String au lieu d'une plus compliqué Logger, même si Array et Logger ne partagent pas explicite interface part le fait qu'ils ont tous les deux une méthode appelée <<.

Un autre exemple est - StringIO, qui implémentent la même Interface que IO , et donc une grande partie de l' Interface d' File, mais sans partager aucun ancêtre commun en plus d' Object.

51voto

caya Points 338

Peut-on exposer des interfaces en Ruby comme nous le faisons en java et appliquer le Rubis de modules ou de classes pour mettre en œuvre les méthodes définies par l'interface.

Ruby n'a pas cette fonctionnalité. En principe, il n'en a pas besoin, comme Ruby utilise ce qu'on appelle le duck-typing.

Il ya quelques approches que vous pouvez prendre.

Écrire des implémentations lever des exceptions; si une sous-classe des tentatives d'utilisation de la méthode non implémentée, il ne sera pas

class CollectionInterface
  def add(something)
    raise 'not implemented'
  end
end

Avec ci-dessus, vous devriez écrire des tests de code qui met en œuvre vos contrats (ce que les autres post ici incorrecte de l'appel de l'Interface)

Si vous vous retrouvez à écrire des méthodes void comme ci-dessus, tout le temps, puis d'écrire un module d'aide qui capte que

module Interface
  def method(name)
    define_method(name) { |*args|
      raise "interface method #{name} not implemented"
    }
  end
end

class Collection
  extend Interface
  method :add
  method :remove
end

Maintenant, combinent le dessus avec Ruby modules et vous êtes proche de ce que vous voulez...

module Interface
  def method(name)
    define_method(name) { |*args|
      raise "interface method #{name} not implemented"
    }
  end
end

module Collection
  extend Interface
  method :add
  method :remove
end

col = Collection.new # <-- fails, as it should

Et puis vous pouvez le faire

class MyCollection
  include Collection

  def add(thing)
    puts "Adding #{thing}"
  end
end

c1 = MyCollection.new
c1.add(1)     # <-- output 'Adding 1'
c1.remove(1)  # <-- fails with not implemented

Permettez-moi de souligner encore une fois: c'est rudimentaire, tout en Ruby qui se passe lors de l'exécution; il n'y a aucun moment de la compilation, la vérification. Si vous couplez cela avec des tests, alors vous devriez être en mesure de ramasser les erreurs. Même encore, si vous prenez le ci-dessus de plus, vous pourriez probablement être en mesure d'écrire une Interface qui effectue la vérification de la classe de première fois un objet de cette classe est créée; faire vos tests aussi simple que d'appeler MyCollection.new... oui, sur le dessus :)

11voto

fotanus Points 6322

Comme tout le monde l'a dit, il n'y a pas de système d'interface pour le rubis. Mais grâce à l'introspection, vous pouvez le mettre en œuvre vous-même assez facilement. Voici un exemple simple qui peut être amélioré de nombreuses manières pour vous aider à démarrer:

 class Object
  def interface(method_hash)
    obj = new
    method_hash.each do |k,v|
      if !obj.respond_to?(k) || !((instance_method(k).arity+1)*-1)
        raise NotImplementedError, "#{obj.class} must implement the method #{k} receiving #{v} parameters"
      end
    end
  end
end

class Person
  def work(one,two,three)
    one + two + three
  end

  def sleep
  end

  interface({:work => 3, :sleep => 0})
end
 

Supprimer l'une des méthodes déclarées sur Person ou changer le nombre d'arguments déclenche une NotImplementedError .

8voto

Daniel Peñalba Points 8548

Le vrai concept d' interface n'existe pas dans Ruby, mais il existe un mécanisme pour le simuler.

Regardez ce post

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X