Help us understand the problem. What is going on with this article?

メソッドの override を強制する

More than 3 years have passed since last update.

概要

継承や Mix-in を利用する際に、特定のメソッドの override を強制したいな。
そのような場合は NotImplementedError を利用すると便利です。

1. 継承の場合

class Mage
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def spell
    "#{job}#{name}#{magic} を唱えた!"
  end

  private

  # サブクラスで必ず実装しておいて欲しい。
  def job
    raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
  end

  # サブクラスで必ず実装しておいて欲しい。
  def magic
    raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
  end
end

class BlackMage < Mage
  private

  def job
    "黒魔道士"
  end
end

class WhiteMage < Mage
  private

  def magic
    "ケアル"
  end
end

class BlueMage < Mage
  private

  def job
    "青魔道士"
  end

  def magic
    "マイティガード"
  end
end

BlackMage.new("ビビ").spell
#=> NotImplementedError: You must implement BlackMage#magic

WhiteMage.new("エーコ").spell
#=> NotImplementedError: You must implement WhiteMage#job

BlueMage.new("クイナ").spell
#=> "青魔道士 の クイナ は マイティガード を唱えた!"

2. Mix-in の場合

module Mage
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def spell
    "#{job}#{name}#{magic} を唱えた!"
  end

  private

  # Mix-in する Class で必ず実装しておいて欲しい。
  def job
    raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
  end

  # Mix-in する Class で必ず実装しておいて欲しい。
  def magic
    raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
  end
end

class BlackMage
  include Mage

  private

  def job
    "黒魔道士"
  end
end

class WhiteMage
  include Mage

  private

  def magic
    "ケアル"
  end
end

class BlueMage
  include Mage

  private

  def job
    "青魔道士"
  end

  def magic
    "マイティガード"
  end
end

BlackMage.new("ビビ").spell
#=> NotImplementedError: You must implement BlackMage#magic

WhiteMage.new("エーコ").spell
#=> NotImplementedError: You must implement WhiteMage#job

BlueMage.new("クイナ").spell
#=> "青魔道士 の クイナ は マイティガード を唱えた!"

このように実装しておけば、
未実装の場合にメソッドを呼び出した際には NotImplementedError が発生し、
例外のメッセージで実装すべきインスタンスメソッドを知らせてくれるので便利です。

3. 発展: クラスアノテーション化する

複数のメソッドに
raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
と書くのは面倒です。
そこで クラスアノテーション として宣言できるようにしてみました。

module NecessaryToOverride
  # 必ず Override すべきメソッドを列挙する。
  def necessary_to_override(*methods)
    methods.each do |method|
      define_method(method) do |*_args|
        raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
      end
    end
  end
end

Module.include(NecessaryToOverride)

以下のように利用します。

3-1. 継承の場合

class Mage
  # サブクラスで job と magic というメソッドを必ず実装しておいて欲しい。
  necessary_to_override :job, :magic

  attr_reader :name

  def initialize(name)
    @name = name
  end

  def spell
    "#{job}#{name}#{magic} を唱えた!"
  end
end

class BlackMage < Mage
  private

  def magic
    "ファイア"
  end
end

BlackMage.new("ビビ").spell
#=> NotImplementedError: You must implement BlackMage#job

3-2. Mix-in の場合

module Mage
  # Mix-in する Class で job と magic というメソッドを必ず実装しておいて欲しい。
  necessary_to_override :job, :magic

  attr_reader :name

  def initialize(name)
    @name = name
  end

  def spell
    "#{job}#{name}#{magic} を唱えた!"
  end
end

class WhiteMage
  include Mage

  private

  def job
    "白魔道士"
  end
end

WhiteMage.new("エーコ").spell
#=> NotImplementedError: You must implement WhiteMage#magic

参考

  • Ruby Patterns
    • 「Overrideしてほしいメソッドの実装にNotImplementedErrorを利用する」の節
QUANON
あんた、マジなんだな?
http://quanon.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした