`
jlaky
  • 浏览: 42884 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Design Patterns in Ruby [Digest 8] Adapter

阅读更多

The Adapter is just like the power adapter such as from 220V to 120V. And when the pin does not fit the socket we need the adapter to fit it.

In software system, we already have a Encrypter to encrypt file:

 

class Encrypter
  def initialize(key)
    @key = key
  end
  def encrypt(reader, writer)
    key_index = 0
    while not reader.eof?
      clear_char = reader.getc
      encrypted_char = clear_char ^ @key[key_index]
      writer.putc(encrypted_char)
      key_index = (key_index + 1) % @key.size
    end
  end
end

 

 

reader = File.open('message.txt')
writer = File.open('message.encrypted','w')
encrypter = Encrypter.new('my secret key')
encrypter.encrypt(reader, writer)

 

And when we want to encrypt a string and we cannot change the Encrypter, we can use the Adapter Pattern:

 

class StringIOAdapter
  def initialize(string)
    @string = string
    @position = 0
  end
  def getc
    if @position >= @string.length
      raise EOFError
    end
    ch = @string[@position]
    @position += 1
    return ch
  end
  def eof?
    return @position >= @string.length
  end
end

 

 

encrypter = Encrypter.new('XYZZY')
reader= StringIOAdapter.new('We attack at dawn')
writer=File.open('out.txt', 'w')
encrypter.encrypt(reader, writer)

 

In ruby we can just modify the class or the instance to implement adapter like requirement.

modify class:

 

 

require 'british_text_object'
# Now add some methods to the original class
class BritishTextObject
  def color
    return colour
  end
  def text
    return string
  end
  def size_inches
    return size_mm / 25.4
  end
end

 

modify instance:

 

bto = BritishTextObject.new('hello', 50.8, :blue)
class << bto
  def color
    colour
  end
  def text
    string
  end
  def size_inches
    return size_mm/25.4
  end
end

 

 

If you modify the original class or object, you do not need the additional adapter class, nor do you need to worry about wrapping the adapter around the adaptee. Things just work. And yet the modification technique involves serious encapsulation violations: You just dive in and start changing things.

 

 

As usual, a pinch of pragmatism seems best. Lean toward modifying the class in the following circumstances:

• The modifications are simple and clear. The method aliasing we did earlier is a prime example of a simple, crystal-clear modification

• You understand the class you are modifying and the way in which it is used. Performing serious surgery on a class without taking a hard look at the class beforehand is probably going to lead to grief.

 

Lean toward an adapter solution in the following situations:

• The interface mismatch is extensive and complex. For example, you probably would not want to modify a string to look like a Fixnum object.

• You have no idea how this class works. Ignorance is always cause to tread lightly

 

The example of Adapter Pattern in Ruby is ActiveRecord database apis:

 

ActiveRecord has to deal with the fact that it needs to talk to a whole crowd of different database systems: MYSQL and Oracle and Postgres, not to mention SQLServer.

All of these database systems provide a Ruby API—which is good.

But all of the APIs are different—which is bad.

 

ActiveRecord deals with all of these differences by defining a standardized interface,

encapsulated in a class called AbstractAdapter. The AbstractAdapter class

defines the interface to a database that is used throughout ActiveRecord.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics