Rubyデザインパターン:テンプレートメソッド

はじめに



ソフトウェア開発分野が拡大するにつれて、開発者は常に最新のテクノロジーをつかもうとしています。 幸いなことに、サポートされているコードを書く技術は言語に依存しません。この一連の投稿では、時代を超越した強力なツールセットであるデザインパターンに焦点を当てます。







Russ Olsenの本、RubyのDesign Patternsを強くお勧めします。 投稿のサイクルはそこからインスピレーションを引き出し、簡単な絞りのようなものになります。 したがって、あなたが読んだものが好きなら(そして私はそう願っています!)、この本は素晴らしい続編になります。



さまざまな設計パターンを検討し、それらを適用する方法を学びます。 今日のトピックは、最も単純なデザインパターンであるテンプレートメソッドです。



建設初日



適切なツール



簡単に言えば、設計パターンはソフトウェアの設計に役立つツールです。 それでも、他のツールと同様に、特定のタスクごとに適切なツールを選択できる必要があります。 もちろん、ハンマーでネジを打つこともできますが、おそらくドライバーを使用するほうが適切です。 多くのデザインパターンのいずれかを使用する前に、解決しようとしている問題を理解することが非常に重要です。



設計パターンを使用して、意図しない問題を解決するのは正しくありません。 言い換えれば、解決するために前述の設計パターンを必要としないタスクにパターンを使用することは、悪い形と見なされます。



壁を作りましょう



今日、私たちの職長は私たちにいくつかの壁を作るように言った。 すべての壁は同じサイズで、同じ素材で作られています(この設計プロジェクトでは、職長から非常に簡単な要件が提示されました)。



#   (Wall) require 'minitest/autorun' describe Wall do let(:wall) { Wall.new } it 'should state its dimensions' do wall.dimensions.must_equal 'I am 30ft. long and 20ft. wide!' end it 'should be made from brick' do wall.made_from.must_equal 'I am made from brick!' end end
      
      





なんて良いボスなのか、彼は私たちに青写真を与えてくれました! 小さいので、壁を作りましょう。



 class Wall def dimensions 'I am 30ft. long and 20ft. wide!' end def made_from 'I am made from brick!' end end
      
      





いいね! 私たちのテストに合格し、みんなが幸せで、ついに夕食に行きます!



ハンマーまたはネイルガン?



私たちが戻ったとき、フォアマンはもっと壁が必要だと言った。 「ここにケーキがあります」と私たちは言った。壁を作るのがどれほど簡単だったかを思い出した。



「みんな、そんなに速くないよ」と監督は異議を唱えた。 新しい壁の要件を持つ新しい設計図があります。



 #    (BrickWall) describe BrickWall do let(:brick_wall) { BrickWall.new } it 'should state its dimensions' do brick_wall.dimensions.must_equal 'I am 30ft. long and 20ft. wide!' end it 'should be made from brick' do brick_wall.made_from.must_equal 'I am made from brick!' end end #    (ConcreteWall) describe ConcreteWall do let(:concrete_wall) { ConcreteWall.new } it 'should state its dimensions' do concrete_wall.dimensions.must_equal 'I am 30ft. long and 20ft. wide!' end it 'should be made from concrete' do concrete_wall.made_from.must_equal 'I am made from concrete!' end end #    (WoodWall) describe WoodWall do let(:wood_wall) { WoodWall.new } it 'should state its dimensions' do wood_wall.dimensions.must_equal 'I am 10ft. long and 20ft. wide!' end it 'should be made from wood' do wood_wall.made_from.must_equal 'I am made from wood!' end end
      
      





うーん...いくつかのアイデアが頭に浮かびました。 Wallクラスの原則に従い、 WoodWall



ConcreteWall



WoodWall



WoodWall



ハードコードされた出力文字列を使用して各メソッドを定義WoodWall



。 考え方は悪くないと思われますが、各インスタンスメソッドをハードコーディングする必要があります。 家庭に数十種類の壁が必要な場合はどうなりますか?



あそこの箱を開けて!



午後のコーヒーを磨きながら、タスクに適したツールであるPatternメソッドパターンがあることに気付きました。



パターンメソッドに続いて、 スケルトンクラス骨格クラス)を作成すると、 サブクラスまたは具象クラスの基盤が構築されます。 スケルトンクラスには抽象メソッドが付属しており、これはサブクラスでオーバーライドできます。 つまり、 Wall



クラス(スケルトンクラス)とそのサブクラスBrickWall



ConcreteWall



WoodWall



ます。



図面を確認した後、3つの異なる壁クラスすべてに、わずかに異なる行を返す#dimensions



および#made_from



が含まれていることに気付きました。 これを念頭に置いて、wallクラスとそのサブクラスを実装しましょう。



 class Wall def dimensions "I am #{length}ft. long and #{width}ft. wide!" end def made_from "I am made from #{material}!" end private def length 30 end end class BrickWall < Wall private def width 20 end def material 'brick' end end class ConcreteWall < Wall private def width 20 end def material 'concrete' end end class WoodWall < Wall private def length 10 end def width 20 end def material 'wood' end end
      
      





議論



フックメソッド



Wall



クラスでは、 BrickWall



ConcreteWall



長さが同じであることがわかるため、プライベートメソッド#length



れています。 WoodWall



クラスについては、値10



返すように#length



を再定義しただけです。 これは、フックメソッドの例です。



フックメソッドは2つの目的に使用されます。

1)骨格実装をオーバーライドし、新しい何かを実装する

2)またはデフォルトの実装を使用します。



スケルトンクラスのデフォルトの実装を定義する必要はありません。 たとえば、次のようにします。



 class Wall ... private def length raise NotImplementedError, 'Sorry, you have to override length' end end class BrickWall < Wall private ... def length 30 end end
      
      





(約-これはルビーのベストプラクティスではありませんが、詳細はこちら 、「継承を必要としない」セクション)



上記の例では、 Wall



クラスの#length



メソッドは、具体的なクラスであるBrickWall



スタブとして#lenght



れています。 本質的に、フックメソッドは、指定されたメソッドをオーバーライドする必要があることをすべての具象クラスに通知します。 基本実装が定義されていない場合、サブクラスはフックメソッドを実装する必要があります。



これが良い壁です



私たちの職長は仕事の結果に魅了されており、おそらくこれが今日の終わりです。 見てきたように、テンプレートメソッドパターンを使用することはまったく難しくありません。 最初に、サブクラスでオーバーライドできる必要なフックメソッドを定義する基本クラスを作成しました。 もちろん、この特定のデザインパターンは考えられる問題を解決するものではありませんが、継承によってコードをクリーンに保つのに役立ちます。



次に、Strategyメソッドについて説明します。 連絡を取り合いましょう!



All Articles