More Related Content Similar to Techtalk design patterns (20) Techtalk design patterns2. A design pattern is a general reusable solution to a commonly
occurring problem within a given context in software design.A
design pattern is not a finished design that can be transformed
directly into source or machine code. It is a description or
template for how to solve a problem that can be used in many
different situations.
The Gang of Four (GoF)
5. class Report!
def initialize!
@title = 'Monthly Report'!
@text = ['Things are going', 'really, really well.']!
end!
!
def output_report(format)!
if format == :plain!
puts("*** #{@title} ***")!
elsif format == :html!
puts('<html>')!
puts(' <head>')!
puts(" <title>#{@title}</title>")!
puts(' </head>')!
puts(' <body>')!
else!
raise "Unknown format: #{format}"!
end!
!
@text.each do |line|!
if format == :plain!
puts(line)!
else!
puts(" <p>#{line}</p>" )!
end!
end!
!
if format == :html!
puts(' </body>')!
puts('</html>')!
end!
end!
end!
6. class Report!
def initialize!
@title = 'Monthly Report'!
@text = ['Things are going', 'really, really well.']!
end!
!
def output_report!
output_start!
output_head!
output_body_start!
@text.each do |line|!
output_line(line)!
end!
output_body_end!
output_end!
end!
!
def output_start!
end!
!
def output_head!
raise 'Called abstract method: output_head'!
end!
!
def output_body_start!
end!
!
def output_line(line)!
raise 'Called abstract method: output_line'!
end!
!
def output_body_end!
end!
!
def output_end!
end!
end!
Template method
7. class HTMLReport < Report!
def output_start!
puts('<html>')!
end!
!
def output_head!
puts(' <head>')!
puts(" <title>#{@title}</title>")!
puts(' </head>')!
end!
!
def output_body_start!
puts('<body>')!
end!
!
def output_line(line)!
puts(" <p>#{line}</p>")!
end!
!
def output_body_end!
puts('</body>')!
end!
!
def output_end!
puts('</html>')!
end!
end!
9. class Report!
attr_reader :title, :text!
attr_accessor :formatter!
!
def initialize(formatter)!
@title = 'Monthly Report'!
@text = ['Things are going', 'really, really well.']!
@formatter = formatter!
end!
!
def output_report!
@formatter.output_report(self)!
end!
end!
!
Report.new(HTMLFormatter.new)
12. class User!
def save!
save_to_database!
if new_record?!
notify_observers(:after_create)!
end!
notify_observers(:after_save)!
end!
end!
!
class UserEmailObserver!
def after_create(user)!
UserMailer.welcome_email(user)!
end!
end!
!
user = User.new!
user.add_observer(UserEmailObserver.new)!
15. class CompositeTask < Task !
def initialize(name)!
super(name)!
@sub_tasks = []!
end!
!
def add_sub_task(task)!
@sub_tasks << task!
end!
!
def remove_sub_task(task)!
@sub_tasks.delete(task)!
end!
!
def get_time_required!
time=0.0!
@sub_tasks.each {|task| time += task.get_time_required}!
time!
end!
end!
16. class MakeCakeTask < CompositeTask!
def initialize!
super('Make cake')!
add_sub_task( MakeBatterTask.new )!
add_sub_task( FillPanTask.new )!
add_sub_task( BakeTask.new )!
add_sub_task( FrostTask.new )!
add_sub_task( LickSpoonTask.new )!
end!
end!
!
MakeCakeTask.new.get_time_required
18. External
array = ['red', 'green', 'blue']!
!
i = ArrayIterator.new(array)!
while i.has_next?!
puts "item: #{i.next_item}"!
end!
Hello Java ;-)
20. External
array1 = [1, 2]!
array1 = [2, 3]!
!
sum = 0!
i1 = ArrayIterator.new(array1)!
i2 = ArrayIterator.new(array2)!
while i1.has_next? && i2.has_next?!
sum += i1.next_item * i2.next_item!
end!
22. PrimerTemplate Method
class SlickButton!
def on_button_push!
raise "Abstract method on_button_push"!
end!
end!
!
class SaveButton < SlickButton!
def on_button_push!
document.save(filename)!
end!
end
So many subclasses :-(
23. class SlickButton!
attr_accessor :command!
!
def initialize(command)!
@command = command!
end!
!
def on_button_push!
@command.execute if @command!
end!
end!
!
class SaveCommand!
def execute!
# Save the current document...!
end!
end!
Command Pattern
26. class Command!
attr_reader :description!
!
def initialize(description)!
@description = description!
end!
!
def execute!
end!
!
def unexecute!
end!
end!
!
class CreateFile < Command!
def initialize(path, contents)!
super "Create file: #{path}"!
@path = path!
@contents = contents!
end!
!
def execute!
f = File.open(@path, "w")!
f.write(@contents)!
f.close!
end!
!
def unexecute!
File.delete(@path)!
end!
end!
27. class CompositeCommand < Command!
def initialize!
@commands = []!
end!
!
def add_command(cmd)!
@commands << cmd!
end!
!
def execute!
@commands.each { |cmd| cmd.execute }!
end!
!
# ...!
!
def unexecute!
@commands.reverse.each { |cmd| cmd.unexecute }!
end!
!
# ...!
!
def description!
description = ''!
@commands.each { |cmd| description += cmd.description + "n" }!
return description!
end!
end!
28. class Installer < CompositeCommand!
def initialize!
add_command(CreateFile.new("file1.txt", "hello worldn"))!
add_command(CopyFile.new("file1.txt", "file2.txt"))!
add_command(DeleteFile.new("file1.txt"))!
end!
end!
!
installer = Installer.new!
installer.execute!
puts installer.description!
30. class Database!
def initialize(adapter)!
@adapter = adapter!
end!
!
def create_table(table_name, fields)!
@adapter.create_table(table_name)!
fields.each_pair do |name, type|!
@adapter.create_column(table_name, name, type)!
end!
end!
end!
!
db = Database.new(MySQLAdapter.new(DB_URI))!
db.create_table(:users, email: :string)!
32. class AccountProtectionProxy!
def initialize(real_account, owner_name)!
@subject = real_account!
@owner_name = owner_name!
end!
!
def withdraw(amount)!
check_access!
return @subject.withdraw(amount)!
end!
!
def check_access!
if Etc.getlogin != @owner_name !
raise "Illegal access: #{Etc.getlogin} cannot
access account."!
end!
end!
end!
34. class UserDecorator!
attr_reader :user!
delegate :first_name, :last_name,!
:position, :institution, to: :user!
!
def initialize(user)!
@user = user!
end!
!
def short_name!
"#{first_name[0]}. #{last_name}"!
end!
!
def description!
"#{short_name} is a #{position} at
#{institution}"!
end!
end!
<p>!
<b>Name:<b>!
{{short_name}}!
<br>!
{{description}}!
<p>!
36. class SimpleLogger!
@@instance = SimpleLogger.new!
!
def self.instance!
return @@instance!
end!
!
def warn(s)!
puts s!
end!
end!
!
SimpleLogger.instance.warn("I don't know what I'm doing")!
38. factory :user do!
first_name 'John'!
last_name 'Doe'!
admin false!
!
factory :admin do!
admin true!
end!
end!
!
FactoryGirl.build(:user)!
FactoryGirl.build(:admin)!
42. AST (Abstract SyntaxTree)
querying stuff, building SQL, etc.
# Files that are bigger than 20KB and not writable,!
# or are mp3 files!
expr = Or.new(!
And.new(Bigger.new(20.kilobytes), Not.new(Writable.new)),!
FileName.new('*.mp3'))!
expr.evaluate # => [File, File, ...]!