Rubyでシングルトンを作成する方法は?
個人的には、4つの方法が思い浮かびます。
方法1:シングルトンを含める
標準ライブラリは、以下を生成するSingleton
モジュールを定義します
クラスに対するいくつかのアクション、特に:
-
.new
プライベートにします - インスタンスを作成および/または返す
.instance
追加します -
#dup
と#clone
をオーバーライドしてエラーを発生させます
これは古典的なシングルトン実装だと思います。 とにかく、私は書くだろう
そのような何か、私はJavaプログラマーになります。 特別なことは何もありません。すべて機能します。
方法2:module_functionを持つモジュール
Module
は、使用できる#module_function
メソッドがあります
自己定義メソッド。 このアプローチは、たとえば、
Math
例:
module M module_function def f :f end end Mf # ==> :f
いくつかの理由から、このようなシングルトンの実装はお勧めしません。
- まだミックスインのままで、別のミックスインに含めることができます
クラス/モジュール。 もちろん、これは恐ろしいことではありませんが、ここで何かが間違っています。 プライベートメソッドは、松葉杖でのみ作成できます。 module_function
メソッド自体のパブリックコピーを作成します。 私はすぐにこれを思いつきました:
module M module_function def f g end def g 'hello' end singleton_class.send(:private, :g) end Mf # ==> 'hello' Mg # ==> NoMethodError
- (個人的な理由)私の意見では
module_function
を使用するモジュールは
何かに役立つステートレスメソッドのコンパイルである。 したがって、
include MyModule
はメソッドの作成にのみ使用されます
MyModule
アクセスせずに現在のモジュールで使用できます。 そのようなシナリオ
使用法は、「Rubyプログラミング言語」のMath
ところで、同じ目的でextend self
を使用extend self
代わりに
module_function
。 これにより、プライベートメソッドの問題が解消されます。 しかし、言いましょう
悪名高いruby-style-guideはこのアプローチを承認していません(リンク:
https://github.com/bbatsov/ruby-style-guide#module-function )
extend self
動作が異なることは明らかだと思いますが、
いくつかの危険な違い。
更新しました。 まだあまり明らかではありません。 extend self
は、モジュールを接続されたモジュールのリストに追加することを強制し(書き込みがどれほど簡単かはわかりません)、 module_function
はメソッドのコピーを作成します。 具体的には、コードを見てください:
module M module_function def f :f end end class A include M end Mf # ==> :f # module_function include A.new.send(:f) # ==> :f module M def f :TROLOLO end end A.new.send(:f) # ==> :TROLOLO Mf # ==> :f
方法3:クラスメソッドのみのクラス/モジュール
class MyClass def self.f :f end def self.g :g end end MyClass.f # ==> :f
または:
class MyClass class << self def f :f end private def g :g end end end MyClass.f # ==> :f MyClass.g # ==> NoMethodError
もちろん、 class
代わりにmodule
を使用できます。 上記で
スタイルガイド、このアプローチは推奨されません。 代わりにお勧め
module_function
。
私の実践では、このアプローチが最も頻繁に遭遇しました。 個人的に、彼はいつも私に見えた
ある種の恐ろしい松葉杖ですが、同時に使用するよりも好きです
Singleton
、として MySingleton.do_something
は私にとってより魅力的に見える
MySingleton.instance.do_something
。
Objectのインスタンスを作成します
最近、私は常にこのアプローチを使用しています:
MySingleton = Object.new class << MySingleton def f g end private def g puts 'hello' end end
これで、シングルトンは必要なメソッドを備えたObject
単なるインスタンスになりました。
MySingleton.class # ==> Object
ここに問題があります:
-
#clone
/#dup
を使用できます。 解決策:このようにオーバーライドします
Singleton
製 - オブジェクトを検査すると、
#<Object: ...>
ようなものが得られ#<Object: ...>
。 解決策:#to_s
および#inspect
オーバーライドします。 ちなみに
ruby-style-guideはこれをすべて自分で行うことを推奨しています(ローカル?
クラスという単語を見つけることができます。 リンク:
https://github.com/bbatsov/ruby-style-guide#define-to-s - 彼らは、このアプローチにはドキュメントの生成に問題があると書いています。 ない
確認または拒否できます ジェネレーターは使用しません。 リンク:
https://practicingruby.com/articles/ruby-and-the-singleton-pattern-dont-get-along
小さな余談:クラス<<自己
私は誰もが構文を見たと思う:
class MyClass class << self def do_something_on_class ... end end def do_something_on_instance ... end end
同時に、私は人がこれが何を意味するか知らないことに繰り返し気づきました
建設。 実際、Rubyでは、オブジェクトには実際に2つのクラスがあります。
そのインスタンスと、いわゆる 「シングルトンクラス」-シングルトンクラス。
確かに、オブジェクトにメソッドを直接定義する例を見ました。
このようなもの:
x = Object.new def x.hey 'hey' end x.hey # ==> 'hey'
クラス指向のOOPでは、オブジェクトに独自のメソッドはありません。 オブジェクトの動作
それが属するクラスによって決定されます。 したがって、決定できません
def x.hey
を使用してオブジェクトのメソッド、クラスで定義する必要があります。 ここに
これを行う場合にのみ、 Object
すべてのインスタンスは
望んでいない#hey
メソッドを取得します。 したがって、Rubyは「追加」を作成します
シングルトンクラスと呼ばれるオブジェクトのクラス。 メソッドを使用して取得できます
#singleton_class
。 一般的に、私は夢中になり、おそらくそうしなかった人だけを混乱させました
「シングルトンクラス」について知っていました。 これはRubyの非常に興味深い部分なので、お勧めします
それについて自分で読んでください。
実際には、要するに、 class << some_object
の構築class << some_object
はclass << some_object
「入ります」
シントン。 比較する:
class A # enter class A scope def hey 'hey' end end class << A # enter class A singleton class scope def hey 'hello' end end A.new.hey # ==> 'hey' A.hey # ==> 'hello'