web-dev-qa-db-ja.com

Rubyでクラスコンストラクターをプライベートにする方法は?

class A
private
  def initialize
    puts "wtf?"
  end
end

A.new #still works and calls initialize

そして

class A
private
  def self.new
    super.new
  end
end

完全には機能しません

では、正しい方法は何ですか? newをプライベートにして、ファクトリメソッドを介して呼び出したいと思います。

50
Leonid Shevtsov

これを試して:

class A
  private_class_method :new
end

APIDockの詳細

76
adurity

試したコードの2番目のチャンクはほぼ正しいです。問題は、privateがクラスメソッドではなくインスタンスメソッドのコンテキストで動作していることです。

privateまたはprivate :newを機能させるには、次のようなクラスメソッドのコンテキストに強制する必要があります。

class A
  class << self
    private :new
  end
end

または、本当にnewを再定義して、superを呼び出したい場合

class A
  class << self
    private
    def new(*args)
      super(*args)
      # additional code here
    end
  end
end

クラスレベルのファクトリメソッドはプライベートnewに問題なくアクセスできますが、newはプライベートであるため、newを使用して直接インスタンス化しようとすると失敗します。

13
Nathan

使用法に光を当てるために、ファクトリメソッドの一般的な例を次に示します。

class A
  def initialize(argument)
    # some initialize logic
  end

  # mark A.new constructor as private
  private_class_method :new

  # add a class level method that can return another type
  # (not exactly, but close to `static` keyword in other languages)
  def self.create(my_argument)
     # some logic
     # e.g. return an error object for invalid arguments
     return Result.error('bad argument') if(bad?(my_argument))

     # create new instance by calling private :new method
     instance = new(my_argument)
     Result.new(instance)
  end
end

次に、それをとして使用します

result = A.create('some argument')    

予想どおり、newを直接使用した場合、ランタイムエラーが発生します。

a = A.new('this leads to the error')
5
Artru