1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

デザインパターンのうち、ProxyパターンとDecorativeパターンを使ったRubyのコード例

2022-02-01 15:24:10

プロキシパターン

要求事項

シャオミンはシャオリーに自分のためにシャオリーを追いかけてくれるように頼んだ(人形、花、チョコレートを送る)

エージェントなしのコード

# -*- encoding: utf-8 -*-

# Pursuit class
class Pursuit
 attr_accessor :mm
 
 def initialize(mm)
  @mm = mm
 end
 
 def give_dolls
  puts "#{mm.name} Send you dolls"
 end
 
 def give_flowers
  puts "#{mm.name} send you flowers"
 end
 
 def give_chocolate
  puts "#{mm.name} send you chocolates"
 end

end

#The pursued class
class Girl
 attr_accessor :name
 
 def initialize(name)
  @name = name
 end
end

xiao_hong = Girl.new('Xiao Hong')

xiao_ming = Pursuit.new(xiao_hong)
xiao_ming.give_dolls
xiao_ming.give_flowers
xiao_ming.give_chocolate



プロキシ専用のコードです。

# -*- encoding: utf-8 -*-

# Proxy class
class Proxy
 attr_accessor :mm
 
 def initialize(mm)
  @mm = mm
 end
 
 def give_dolls
  puts "#{mm.name} Send you dolls"
 end
 
 def give_flowers
  puts "#{mm.name} send you flowers"
 end
 
 def give_chocolate
  puts "#{mm.name} send you chocolates"
 end

end

#The pursued class
class Girl
 attr_accessor :name
 
 def initialize(name)
  @name = name
 end
end

xiao_hong = Girl.new('Xiao Hong')

xiao_ming = Proxy.new(xiao_hong)
xiao_ming.give_dolls
xiao_ming.give_flowers
xiao_ming.give_chocolate



pursuer クラスを proxy クラスに置き換えるだけです。

実際のプロキシパターンのコードです。

# -*- encoding: utf-8 -*-

# public interface module
module GiveGift
 def give_dolls
 end
 
 def give_flowers
 end
 
 def give_chocolate
 end
end

# Pursuit class
class Pursuit
 include GiveGift
 attr_accessor :mm, :name
 
 def initialize(mm)
  @mm = mm
 end
 
 def give_dolls
  puts "#{mm.name} Send you dolls for #{name}"
 end
 
 def give_flowers
  puts "#{mm.name} send you flowers for #{name}"
 end
 
 def give_chocolate
  puts "#{mm.name} send you chocolates for #{name}"
 end

end

#Proxy Class
class Proxy
 include GiveGift
 attr_accessor :gg
 
 def initialize(mm)
  @gg = Pursuit.new(mm)
 end
 
 def give_dolls
  gg.give_dolls
 end
 
 def give_flowers
  gg.give_flowers
 end
 
 def give_chocolate
  gg.give_chocolate
 end

end

#The pursued class
class Girl
 attr_accessor :name
 
 def initialize(name)
  @name = name
 end
end

xiao_hong = Girl.new('Xiao Hong')

xiao_ming = Proxy.new(xiao_hong)
xiao_ming.gg.name = '小明'
xiao_ming.give_dolls
xiao_ming.give_flowers
xiao_ming.give_chocolate




デコレーションパターン

必要条件

マッチング

コードバージョン1

# -*- encoding: utf-8 -*-

class Person
 attr_accessor :name
 
 def initialize(name)
  @name = name
 end
 
 def wear_t_shirts
  puts 'big t-shirt'
 end
 
 def wear_big_trouser
  puts 'pants'
 end
 
 def wear_sneakers
  puts 'broken sneakers'
 end
 
 def wear_suit
  puts 'suit'
 end
 
 def wear_tie
  puts 'tie'
 end
 
 def wear_leather_shoes
  puts 'leather shoes'
 end
 
 def show
  puts "***** dress up #{name}\n\n"
 end

end


xc=Person.new('dish')
puts "****** first dress up"
xc.wear_t_shirts
xc.wear_big_trouser
xc.wear_sneakers
xc.show

puts "****** second_dressup"
xc.wear_suit
xc.wear_tie
xc.wear_leather_shoes
xc.show



問題は、"Superman" のコスチュームを追加する場合、Personクラスを修正しなければならず、オープンクローズの原則に違反していることです。

コードバージョン2

# -*- encoding: utf-8 -*-

class Person
 attr_accessor :name
 
 def initialize(name)
  @name = name
 enddef show
  puts "***** dressed up as #{name}\n\n"
 end

end


class Finery
 def show
 end
end

class TShirts < Finery
 def show
  puts 'big t-shirt'
 end
end

class BigTrouser < Finery
 def show
  puts 'slacks'
 end
end

class Sneakers < Finery
 def show
  puts 'broken sneakers'
 end
end

class Suit < Finery
 def show
  puts 'Suit'
 end
end

class Tie < Finery
 def show
  puts 'tie'
 end
end


class LeatherShoes < Finery
 def show
  puts 'leather shoes'
 end
end


xc = Person.new('small dish')
ts = TShirts.new
bt = BigTrouser.new
sk = Sneakers.new
puts "****** first dress"
ts.show
bt.show
sk.show
xc.show


suit = Suit.new
tie = Tie.new
ls = LeatherShoes.new
puts "****** second dress"
suit.show
tie.show
ls.show
xc.show



このように変更した結果、スーパーマンのコスチュームを追加しても、本当にPersonクラスを修正する必要はありません。問題は、様々な衣装が別々に公開され、ただ一つずつ順番に着ていくだけで、制御不能になることです。

コードバージョン3

# -*- encoding: utf-8 -*-

class Person
 attr_accessor :name
 
 def initialize(name=nil)
  @name = name
 end
 
 def show
  puts "***** dressed up as #{name}\n\n"
 end

end


class Finery < Person
 attr_accessor :componet

 def decorate(componet)
  @componet = componet
 end

 def show
  componet.show if componet
 end
end

class TShirts < Finery
 def show
  super
  puts 'big t-shirt'
 end
end

class BigTrouser < Finery
 def show
  super
  puts 'collapsed pants'
 end
end

class Sneakers < Finery
 def show
  super
  puts 'broken sneakers'
 end
end

class Suit < Finery
 def show
  super
  puts 'Suit'
 end
end

class Tie < Finery
 def show
  super
  puts 'tie'
 end
end


class LeatherShoes < Finery
 def show
  super
  puts 'leather shoes'
 end
end


xc = Person.new('small dish')
ts = TShirts.new
bt = BigTrouser.new
sk = Sneakers.new
puts "****** first dress"
ts.decorate xc
bt.decorate ts
sk.decorate bt
sk.show


suit = Suit.new
tie = Tie.new
ls = LeatherShoes.new
puts "****** second dress"
suit.decorate xc
tie.decorate suit
ls.decorate bt
ls.show