Rubyのデザインパターン。プログラミングにおけるシングルトンパターンの活用
はじめに
シングルトンパターンは、デザインパターンの中でも最もシンプルな形の一つである。このパターンの目的は、あるクラスのオブジェクトを、システム内でそのクラスの唯一のインスタンスにすることです。これを実現するためには、まずクライアント側でインスタンス化することから始めます。そのため、オブジェクトクラスのユニークなインスタンスのみを生成できるような仕組みで、生成したいオブジェクトへのアクセスをすべて"block"する必要がある。インスタンス生成処理を制限するために、ファクトリーメソッドを使用する。このメソッドは静的メソッド(クラスメソッド)であるべきです。なぜなら、クラスのインスタンスが別の一意のインスタンスを生成することは意味がないからです。
キーポイント
1つは、クラスは1つのインスタンスしか持てないこと、2つは、そのインスタンスを自分で生成しなければならないこと、3つは、そのインスタンスをシステム全体に提供しなければならないことです。
具体的な実装としては、1、シングルトンパターンのクラスはプライベートコンストラクタのみを提供する、2、クラス定義にそのクラスの静的プライベートオブジェクトを含む、3、そのクラスが
シングルトン
classClassVariableTester
@@class_count = 0
def initialize
@instance_count = 0
end
def increment
@@class_count = @@class_count + 1
@instance_count = @instance_count + 1
end
def to_s
"class count :#{@@class_count} -- instance count :#{@instance_count}"
end
end
cv1 = ClassVariableTester.new
cv1.increment
cv1.increment
puts("cv1:#{cv1}")
cv2 = ClassVariableTester.new
puts("cv2:#{cv2}")
#cv1:class count :2 -- instance count :2
#cv2:class count :2 -- instance count :0
2つ目のオブジェクトが生成されたとき、@@class_countは2、ii@instance_countは0ですが、クラス変数はすべてのインスタンスで共有されているので、@@class_countが2になってからパーティcv1.includeが2回呼ばれます。 2つ目のClassVariableTesterオブジェクトcv2が作られたとき、@@class_countは共有されていたのでこの時点でも@@class_countが2になっています。
また、インスタンス変数は現在のオブジェクトにしか使えないので、インスタンスオブジェクト cv2 の @@instance_count は 0 になっています。
このクラス変数の特徴は、シングルインスタンスパターン
class SimpleLogger
@@instance = SimpleLogger.new
def self.get_instance
@@instance
end
private_class_method :new
end
sl1 = SimpleLogger.get_instance
sl2 = SimpleLogger.get_instance
puts sl1 == sl2
結果は: true 。
クラス変数はクラスのインスタンスを1つだけ保持するために使用され、クラスメソッドはこの1つのインスタンスを返すために必要です。
しかし、別のインスタンスオブジェクトを SimpleLogger.new で作成することは可能なので、new メソッドは private にする必要があります。
sl3 = SimpleLogger.new
private method `new' called for SimpleLogger:Class (NoMethodError)
require 'singleton'
class SimpleLogger
include Singleton
end
#puts SimpleLogger.new
sl1 = SimpleLogger.instance
sl2 = SimpleLogger.instance
puts sl1 == sl2
結果は、「真」です。
シングルトンは、Rubyのクラスライブラリで提供されており、シングルトン・クラスの作成を簡素化することができます。
シングルトンに混ぜることで、クラス変数の作成、シングルトンインスタンスの初期化、クラスレベルのインスタンスメソッドの作成、new privateの作成が省かれます。
SimpleLogger.instanceでロガーのインスタンスを1つ取得します。
しかし、この2つのアプローチには違いがあります。
1つ目のアプローチは、「イーガー・インスタンス」と呼ばれています。
インスタンスオブジェクトは、実際に必要となる前に作成されます。
2つ目の方法は、「遅延インスタンス化(lazy instantiation)」と呼ばれます。
インスタンスが呼び出されたときに作成されます。
しかし、このSingletonは実際には何も防ぐことができません。public_class_methodを使って、新しいメソッドをパブリックなものに変更するために使用することができます。
クラスを開き、新しいメソッドをpublicに設定したら、SimpleLogger.newを使ってオブジェクトを作成します。
class SimpleLogger
public_class_method :new
end
puts SimpleLogger.new
さらに2つのケースで。
(i) グローバル変数の使用、グローバル変数はプログラムと密結合しているため、グローバル変数を使用しないようにする。
実は、シングルトンパターンもグローバル変数も同じように機能するのです。
$logger = SimpleLogger.new
(ii) クラスを1つのインスタンスとして使用することで
class SimpleLogger
WARNING = 1
INFO = 2
def initialize(file)
@@log = File.open(file, "w")
@@level = WARNING
end
def self.warning(msg)
puts @@level > WARNING
@@log.puts(msg) if @@level > WARNING
@@log.flush
end
def self.level
@@level
end
def self.level = (new_level)
@@level = new_level
end
end
SimpleLogger.new("test.txt")
puts SimpleLogger.level
SimpleLogger.level = SimpleLogger::INFO
puts SimpleLogger.level
SimpleLogger.warning("warning")
インスタンス
require 'rubygems'
require 'watir'
require 'singleton'
class AutoTest
include Singleton
def OpenUrl(url)
@browser= Watir::Browser.new
@browser.goto(url)
@url=url
end
def set_textarea(text)
@browser.text_field(:id,'kw').set(text)
end
def click
@browser.button(:id,'su').click
end
end
test,test2 = AutoTest.instance
test.OpenUrl('http://www.baidu.com')
test.set_textarea('aslandhu')
test.click
ここでは、AutoTest のインスタンスが 2 つ作成されますが、2 つ目のインスタンスは実際には nil であり、これは正常に作成されなかったことを意味します。
require 'rubygems'
require 'watir'
require 'singleton'
require 'thread'
class TestOneObj
end
class <<TestOneObj
include Singleton
def instance
@browser= Watir::Browser.new
self
end
def openurl(url)
@browser.goto(url)
end
def set_textarea(text)
@browser.text_field(:id,'kw').set(text)
end
def click
@browser.button(:id,'su').click
end
end
test = TestOneObj.instance
test2 = TestOneObj.instance
p test.inspect
p test2.inspect
test.openurl('www.baidu.com')
test2.set_textarea('aslandhu')
test.click
上記のコードでは、2つのBrowserオブジェクトを作成しようとしていますが、実際には作成されるオブジェクトは両方とも同じものです。IE のウィンドウが 2 つ開かれていますが、オブジェクトは 1 つです。つまり、test と test2 は同じオブジェクトです。
関連
-
画像フィルターアルゴリズムコードのRuby実装
-
UbuntuでRuby on RailsフレームワークとRubyMine IDEを設定する
-
Ruby Hash ハッシュ型 基本操作のメソッド一覧 まとめ
-
Nokogiriパッケージを使ってXML形式のデータを操作するためのRubyチュートリアル
-
RubyでXMLデータ処理ライブラリREXMLを使うための手引き
-
Rubyでタスクビルダーのrakeを使い始める
-
Builderビルダーパターンを用いたRubyデザインパターンプログラミング例
-
rubyのダブルイコール==問題
-
Rubyのバージョンを管理するためのrbenvの使い方
-
Rubyのメソッドを検索して実行する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
PythonのFlaskフレームワークでSERVER_NAMEドメイン名を設定するためのチュートリアル
-
RubyのMonkey Patchの開発例
-
Windowsでrubyとrailsをインストールする際に発生する問題点まとめ
-
Rubyプログラムにおける正規表現の基本的な使い方に関するチュートリアル
-
Jekyll静的ウェブサイトのバックエンドエンジンのチュートリアル
-
RubyのプログラムでXML形式のデータをパースするためにREXMLを呼び出す例
-
RubyアプリケーションでHTTPベースのリクエストを送信する簡単な例
-
Ruby WebDriverガイド
-
Rubyの変数参照に関するいくつかの注意点
-
Rubyのクラスとモジュールの書き方のスタイルガイド