135 votes

Comment implémenter une classe abstraite en ruby?

Je sais qu'il n'y a pas de concept de classe abstraite en ruby. Mais si cela doit être mis en œuvre, comment s'y prendre? J'ai essayé quelque chose comme ...

 class A
  def self.new
    raise 'Doh! You are trying to instantiate an abstract class!'
  end
end

class B < A
  ...
  ...
end
 

Mais lorsque j'essaie d'instancier B, il appelle en interne A.new ce qui déclenche l'exception.

De plus, les modules ne peuvent pas être instanciés, mais ils ne peuvent pas non plus être hérités. rendre la nouvelle méthode privée ne fonctionnera pas non plus. Des pointeurs?

128voto

Yar Points 25421

Juste à carillon tard ici, je pense qu'il n'y a pas de raison d'arrêter quelqu'un à partir de l'instanciation de la classe abstraite, en particulier parce qu'ils peuvent ajouter des méthodes à la volée.

Duck-typing langues, comme le Rubis, la présence/absence ou le comportement de méthodes lors de l'exécution afin de déterminer si elles devraient être appelée ou non. Donc à votre question, tel qu'il s'applique à un résumé de la méthode, sens

def get_db_name
   raise 'this method should be overriden and return the db name'
end

et qui devrait être sur la fin de l'histoire. La seule raison d'utiliser les classes abstraites en Java consiste à insister pour que certaines méthodes get "rempli", alors que d'autres ont de leur comportement dans la classe abstraite. Dans un canard en tapant la langue, l'accent est mis sur les méthodes, pas sur les classes/types, de sorte que vous devez déplacer vos soucis à ce niveau.

Dans votre question, vous êtes essentiellement en essayant de recréer l' abstract mot clé de Java, qui est un code-odeur pour faire du Java dans Ruby.

62voto

nakajima Points 1266

Je n'aime pas utiliser les classes abstraites en Ruby (il y a presque toujours un meilleur moyen). Si vous pensez vraiment que c'est la meilleure technique pour la situation, vous pouvez utiliser l'extrait suivant pour être plus déclaratif sur les méthodes abstraites:

 module Abstract
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def abstract_methods(*args)
      args.each do |name|
        class_eval(<<-END, __FILE__, __LINE__)
          def #{name}(*args)
            raise NotImplementedError.new("You must implement #{name}.")
          end
        end
      end
    end
  end
end

require 'rubygems'
require 'spec'

describe "abstract methods" do
  before(:each) do
    @klass = Class.new do
      include Abstract

      abstract_methods :foo, :bar
    end
  end

  it "raises NotImplementedError" do
    proc {
      @klass.new.foo
    }.should raise_error(NotImplementedError)
  end

  it "can be overridden" do
    subclass = Class.new(@klass) do
      def foo
        :overridden
      end
    end

    subclass.new.foo.should == :overridden
  end
end
 

En gros, vous appelez simplement abstract_methods avec la liste des méthodes abstraites. Lorsqu'elles sont appelées par une instance de la classe abstraite, une exception NotImplementedError est générée.

47voto

Andrew Peters Points 6012

Essaye ça:

 class A
  def initialize
    raise 'Doh! You are trying to instantiate an abstract class!'
  end
end

class B < A
  def initialize
  end
end
 

20voto

bluehavana Points 378
class A
  private_class_method :new
end

class B < A
  public_class_method :new
end

13voto

Austin Ziegler Points 409

Au cours des six dernières années et demie de programmation de Ruby, je n'ai jamais eu besoin d' un cours d'abstraction.

Si vous pensez avoir besoin d'un cours abstrait, vous pensez trop dans un langage qui les fournit / le requiert, pas en Ruby en tant que tel.

Comme d'autres l'ont suggéré, un mixin est plus approprié pour les éléments supposés être des interfaces (comme les définit Java) et il est plus approprié de repenser votre conception pour les éléments "nécessitant" des classes abstraites d'autres langages tels que C ++.

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