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.