概要
Use transparent adapters to gradually introduce abstraction
前提
Confident Rubyではメソッド内の処理を次のように分類しています。
・Collecting Inputs(引数チェック、変換など)
・Performing Work(主処理)
・Delivering Output(戻り値に関わる処理)
・Handling Failure(例外処理)
当記事は上記のうち、Collecting Inputsに関する話です。
詳細
状況
以前から存在するAdapterの導入が困難な特定の型のCollaboratorへの依存性を多く持ったクラス
概要
委譲によってAdapterを作成し、より依存性の低い設計への変更を容易にする。
理由
私たちが一度に少しのステップごとに成し遂げるならば、コード内の関心の分離を改善することは、より親しみやすい問題です。
サンプルコード仕様
数値、文字列、配列、三角形、四角形のクラスをX倍にする
メソッドを定義します。
※三角形、四角形クラスは直接変更不可能,という制約があるものとしてDelegateClassを利用して委譲する
サンプルコード(委譲アダプタを利用しない場合)
require 'pp' def multiply(input, count) case input when Triangle Triangle.new(input.width * count, input.height * count) when Square Square.new(input.width * count, input.height * count) else input*count end end class Triangle attr_accessor :width, :height def initialize(width, height) @width, @height = width, height end def area @width * @height / 2.0 end end class Square attr_accessor :width, :height def initialize(width, height) @width, @height = width, height end def area @width * @height end end puts multiply(3, 4) puts multiply("abc", 2) print multiply([1,2,3], 2), "\n" triangle = multiply(Triangle.new(2, 3), 2) square = multiply(Square.new(2, 3), 2) pp triangle puts triangle.area pp square puts square.area
12 abcabc [1, 2, 3, 1, 2, 3] #<Triangle:0x26a9570 @height=6, @width=4> 12.0 #<Square:0x26a9510 @height=6, @width=4> 24
サンプルコード(委譲アダプタを利用した場合)
require 'pp' require 'delegate' class Triangle attr_accessor :width, :height def initialize(width, height) @width, @height = width, height end def area @width * @height / 2.0 end end class Square attr_accessor :width, :height def initialize(width, height) @width, @height = width, height end def area @width * @height end end class MultiplyTriangle < DelegateClass(Triangle) def initialize(width, height) super(Triangle.new(width, height)) end def *(other) self.width = width * other self.height = height * other self end end class MultiplySquare < DelegateClass(Square) def initialize(width, height) super(Square.new(width, height)) end def *(other) self.width = width * other self.height = height * other self end end class Multiplyer def multiply(input, count) input*count end end puts Multiplyer.new.multiply(3, 4) puts Multiplyer.new.multiply("abc", 2) print Multiplyer.new.multiply([1,2,3], 2), "\n" triangle = Multiplyer.new.multiply(MultiplyTriangle.new(2, 3), 2) square = Multiplyer.new.multiply(MultiplySquare.new(2, 3), 2) puts triangle.area puts square.area
12 abcabc [1, 2, 3, 1, 2, 3] #<Triangle:0x26a9570 @height=6, @width=4> 12.0 #<Square:0x26a9510 @height=6, @width=4> 24