Last active
December 19, 2015 10:19
-
-
Save anildigital/5939892 to your computer and use it in GitHub Desktop.
I gave talk on 'Design Patterns in Ruby' at Pune Ruby Users Group meetup at ThoughtWorks. Here are the slides https://speakerdeck.com/anildigital/design-patterns-in-ruby And below are the code snippets which I used to demo.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Example from http://www.takadevelop.com/2013/05/03/adapter-pattern-in-ruby/ | |
# Adapter Design Pattern | |
# Abstract Duck | |
class Duck | |
def quack | |
end | |
def fly | |
end | |
end | |
# Abstrack Turkey | |
class Turkey | |
def gobble | |
end | |
def fly | |
end | |
end | |
# Weird Duck | |
class WeirdDuck < Duck# Adaptee | |
def quack | |
"quack" | |
end | |
def fly | |
"I'm flying" | |
end | |
end | |
# Wild Turkey | |
class WildTurkey < Turkey | |
def gobble | |
"Gobble Gobble" | |
end | |
def fly | |
"I'm flying a short distance" | |
end | |
end | |
# Turkey to Duck Adapter | |
class TurkeyToDuckAdapter # < Duck | |
attr_reader :turkey | |
def initialize(turkey) | |
@turkey = turkey | |
end | |
def quack | |
@turkey.gobble | |
end | |
def fly | |
@turkey.fly | |
end | |
end | |
wildturkey = WildTurkey.new | |
duck_like_turkey = TurkeyToDuckAdapter.new(wildturkey) | |
puts duck_like_turkey.quack | |
puts duck_like_turkey.fly |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Example from ported from example in Design Patterns in Ruby book by Russ Olsen | |
# Composite Design Pattern | |
# Task class | |
class Task | |
attr_reader :name | |
def initialize(name) | |
@name = name | |
end | |
def get_time_required | |
0.0 | |
end | |
end | |
# Concrete requirement anaylysis task | |
class RequirementAnalysis < Task | |
def initialize | |
super("Requirement Analysis") | |
end | |
def get_time_required | |
2.0 | |
end | |
end | |
# Concrete generate mockups task | |
class Mockup < Task | |
def initialize | |
super("Requirement Analysis") | |
end | |
def get_time_required | |
1.0 | |
end | |
end | |
# Concrete coding task | |
class Code < Task | |
def initialize | |
super("Code Task") | |
end | |
def get_time_required | |
1.0 | |
end | |
end | |
# Concrete testing task | |
class Test < Task | |
def initialize | |
super("Test Software") | |
end | |
def get_time_required | |
1.0 | |
end | |
end | |
# Concrete ship task | |
class Ship < Task | |
def initialize | |
super("Deploy Software! Ship it!") | |
end | |
def get_time_required | |
0.0 | |
end | |
end | |
# Composite class | |
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 | |
class ShipSoftware < CompositeTask | |
def initialize | |
super('Ship software') | |
add_sub_task( RequirementAnalysis.new ) | |
add_sub_task( Mockup.new ) | |
add_sub_task( Code.new ) | |
add_sub_task( Test.new ) | |
add_sub_task( Ship.new ) | |
end | |
end | |
ship_software = ShipSoftware.new | |
puts ship_software.get_time_required |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Example ported from Java example on http://ruby019.wordpress.com/2012/11/27/decorator-design-pattern-3/ | |
# Decorator Design Pattern | |
# Original Kindle class | |
class Kindle | |
def description | |
"Kindle Paperwhite" | |
end | |
def weight | |
213 | |
end | |
def price | |
10999 | |
end | |
end | |
# Decorator class | |
class KindleDecorator < Kindle | |
def initialize(kindle) | |
@kindle = kindle | |
end | |
def description | |
@kindle.description | |
end | |
def weight | |
@kindle.weight | |
end | |
def price | |
@kindle.price | |
end | |
end | |
# Bag decorator | |
class Bag < KindleDecorator | |
def initialize(kindle) | |
@kindle = kindle | |
end | |
def description | |
@kindle.description + ", bag" | |
end | |
def weight | |
@kindle.weight + 30 | |
end | |
def price | |
@kindle.price + 1000 | |
end | |
end | |
# Adapter decorator | |
class Adapter < KindleDecorator | |
def initialize(kindle) | |
@kindle = kindle | |
end | |
def description | |
@kindle.description + ", adapter" | |
end | |
def weight | |
@kindle.weight + 50 | |
end | |
def price | |
@kindle.price + 1200 | |
end | |
end | |
kindle_with_bag_and_adapter = Adapter.new(Bag.new(Kindle.new)) | |
puts "Package: Kindle With Bag And Adapter"; | |
puts "Description: " + kindle_with_bag_and_adapter.description; | |
puts "Weight: " + kindle_with_bag_and_adapter.weight.to_s + " gm"; | |
puts "Price: ₹" + kindle_with_bag_and_adapter.price.to_s; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Example from Design Patterns in Ruby book by Russ Olsen | |
# Proxy Design Pattern | |
class BankAccount | |
attr_reader :balance | |
def initialize(starting_balance=0) | |
@balance = starting_balance | |
end | |
def deposit(amount) | |
@balance += amount | |
end | |
def withdraw(amount) | |
@balance -= amount | |
end | |
end | |
# class BankAccountProxy | |
# def initialize(real_object) | |
# @real_object = real_object | |
# end | |
# def balance | |
# @real_object.balance | |
# end | |
# def deposit(amount) | |
# @real_object.deposit(amount) | |
# end | |
# def withdraw(amount) | |
# @real_object.withdraw(amount) | |
# end | |
# end | |
# account = BankAccount.new(100) | |
# account.deposit(50) | |
# account.withdraw(10) | |
# proxy = BankAccountProxy.new(account) | |
# proxy.deposit(50) | |
require 'etc' | |
class AccountProtectionProxy | |
def initialize(real_account, owner_name) | |
@subject = real_account | |
@owner_name = owner_name | |
end | |
def deposit(amount) | |
check_access | |
return @subject.deposit(amount) | |
end | |
def withdraw(amount) | |
check_access | |
return @subject.withdraw(amount) | |
end | |
def balance | |
check_access | |
return @subject.balance | |
end | |
def check_access | |
if Etc.getlogin != @owner_name | |
raise "Illegal access: #{Etc.getlogin} cannot access account." | |
end | |
end | |
end | |
account = BankAccount.new(100) | |
account.deposit(50) | |
account.withdraw(10) | |
proxy = AccountProtectionProxy.new(account, "anil") | |
proxy.deposit(50) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Example from Design Patterns in Ruby book by Russ Olsen | |
# Strategy Design Pattern | |
class Report # Context | |
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 | |
class HTMLFormatter # Strategy 1 | |
def output_report(context) | |
puts('<html>') | |
puts(' <head>') | |
# Output The rest of the report ... | |
puts(" <title>#{context.title}</title>") | |
puts(' </head>') | |
puts(' <body>') | |
context.text.each do |line| | |
puts(" <p>#{line}</p>") | |
end | |
puts(' </body>') | |
puts('</html>') | |
end | |
end | |
class PlainTextFormatter # Strategy 2 | |
def output_report(context) | |
puts("***** #{context.title} *****") | |
context.text.each do |line| | |
puts(line) | |
end | |
end | |
end | |
# Pass strtegy object to the context | |
report = Report.new(HTMLFormatter.new) | |
report.output_report |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Template Method Design pattern | |
# Game | |
class Game | |
# Template method .. YES it is template method! | |
def play_game | |
perform_step1 | |
perform_step2 | |
perform_step3 | |
end | |
def perform_step1 | |
raise "must be implemented by a class" | |
end | |
def perform_step2 | |
raise "must be implemented by a class" | |
end | |
def perform_step3 | |
raise "must be implemented by a class" | |
end | |
end | |
# Chess | |
class Chess < Game | |
def perform_step1 | |
puts "Start Chess game" | |
end | |
def perform_step2 | |
puts "Play Chess" | |
end | |
def perform_step3 | |
puts "Declare winner or tie" | |
end | |
end | |
# Monopoly | |
class Monopoly < Game | |
def perform_step1 | |
puts "Start Monopoly game" | |
end | |
def perform_step2 | |
puts "Play Monopoly" | |
end | |
def perform_step3 | |
puts "Declare Monopoly winner" | |
end | |
end | |
puts Chess.new.play_game | |
puts Monopoly.new.play_game |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment