CSC/ECE 517 Fall 2010/ch7 7a AV

From Expertiza_Wiki
Jump to navigation Jump to search

Novel implementations of design patterns in dynamic languages

Design Pattern

It is a template that provides a description of good design alternatives for the benefit of programmers. It is used to provide recurring solutions to design patterns in both static and dynamic object oriented languages. 5 2

Importance of design patterns in programming languages

i. In a given context, design patterns can be a reusable solution for a general problem. 1
ii. For the benefit of novice programmers, design patterns are usually documented systematically.
iii. Design patterns help us to learn from the experience of other software developers.
iv. Design patterns are a framework for evolution and improvement of existing patterns.
v. It provides better abstraction for program organization.

How to choose a particular design pattern?

i. Identify the different classes and methods for a given problem. 3
ii. Recognize the different solutions that can be used to solve the problem.
iii. Compare and contrast the trade offs between the design patterns that can be used for that particular context.
iv. Recognize the language limitations for each of the design patterns.
v. Finally choose the most suitable and efficient design.

Design patterns in dynamic programming languages

As dynamic languages need less overhead for bookkeeping (classes, methods) therefore design patterns are easier to use in dynamic languages. Dynamic o-o languages do not have class-restricted design, Hence design patterns are simpler and flexible. 11 chapter1

Some design patterns have novel implementation in dynamic languages. The alternative ways of implementing design patterns ( such as observer, decorator, iterator) is being discussed here. 4

Observer Pattern

This pattern is used in the context, where frequent updates of different states take place. It becomes an overhead if each object has to check whether the state has been updated or not. Hence all such objects (called the “observers”) register themselves to another object (“subject”). The subject is responsible to keep check on the object, and notify the observers when a change of state takes place. 6

Fig 5.1 Use Case diagram for Observer pattern

This pattern is used in the context, where frequent updates of different states take place. It becomes an overhead if each object has to check whether the state has been updated or not. Hence all such objects (called the “observers”) register themselves to another object (“subject”). The subject is responsible to keep check on the object, and notify the observers when a change of state takes place. 8

Implementation of observer pattern in ruby

module Observable #subject module which checks for update and notifies
def ModifyPrice( &callObservers )
@observers = [] 
@observers << callObservers
end


def notify_observers
@observers.each { |o| o.call } 
end
end


class Seller             #state that is checked frequently is price.
include Observable
attr :price
def initialize( price = 10 )
@price = price
end



def increasePrice       
@price = @price +  2.5
notify_observers
end

def decreasePrice
@price = @price -  0.5
notify_observers
end

end
StoreKeeper = Seller.new
StoreKeeper.ModifyPrice do        #updates price and then notifies 
puts "The new price of the product is #{StoreKeeper.price}"
end

StoreKeeper.increasePrice
StoreKeeper.decreasePrice
StoreKeeper.increasePrice


Output

The new price of the product is 12.5 The new price of the product is 12.0 The new price of the product is 14.5

In the above example, we have the observable module that checks if a particular state is being updated or not. When the update happens the notify function is immediately called. We maintain a seller class that uses the observable module, when the seller increases or decreases the price of a product the notify_observers is called which then calls the modify_price which prints the new price. This program uses observer pattern in a novel way using closures which differs from its implementation in any other static language.

Decorator Pattern

This design pattern is used when additional functionalities have to be given to a particular class in a dynamic manner. It is an alternative for subclassing and inheritance (which is done statically). The most common application of decorator patterns is in designing of GUI toolkit. 7

Fig 6.1 Use Case diagram for Observer pattern

Implementation of Decorator pattern in ruby

	
module Decorator
 def initialize(decorated)
    @decorated = decorated
  end
end
class SimplePizza
  def price
    @price = 5
     end
end


class OnionTopping
 include Decorator

  def price
    @price = @decorated.price+ 1.1
   end
end
class CheeseTopping
  include Decorator

  def price
    @decorated.price + 1.0
  end
end
#Price of Pizza without decoration(no toppings)
 puts "price of pizza without Topping #{SimplePizza.new.price}"

#Price of Pizza with OnionToppings (decorater used here)
#initialise OnionTopping class as a decorator for the class SimplePizza
OTPizza =OnionTopping.new(SimplePizza.new)

puts "price of pizza with OnionTopping #{OTPizza.price}"

TwoTopping = CheeseTopping.new(OnionTopping.new(SimplePizza.new))
puts "price of pizza with cheese and Onion toppings #{TwoTopping.price}"

output

price of pizza without Topping 5 price of pizza with OnionTopping 6.1 price of pizza with cheese and Onion toppings 7.1

In the example above, we have a class called SimplePizza which initializes the cost of a pizza without any toppings. There might be a situation where a customer would want a pizza with a topping instead writing the price for each type of pizza. For this porpose we use decorator patterns. 9

Here the SimplePizza is the base class. The OnionToppingPizza and cheeseToppingPizza classes are the decorators used for this base class. This program dynamically calculates the price of each pizza depending on the choice of topping.

Advantage: Altough we dint write a class to calculate the price of a TwoToppingPizza, The decorator pattern used in this program was able to calculate the price of TwotoppingPizzza accurately.

Iterator pattern

Iterator design pattern is used to traverse each element of a collection object sequentially. While using the iterator, the programmer need not worry about the underlying interface of the collection object.The iterator interface usually consists of hasNext( ),next( ), isDone( ) functions. 10

Fig 7.1 Use Case diagram for Iterator pattern

Implementation of Iterator pattern in ruby

Example 1 square_arrayElements

This is a simple example where in an iterator each is used to print the square of each element in an array using closures.

def square_arrayElements (array)
    array.each {|a| puts a*a } 
        end
  
array = [1,2,3,5]
square_arrayElements(array)


Output:
1
4
9
25
The array elements 1,2,3,4 is passed to the function square_arrayElements. The iterator parses each element and sends it to the block where the square of each element is calculated and prints it.

Example 2 EvenOrOdd

In below program, the iterator traverses through each element of the array and checks if the element is odd or even. This check is performed in the block which prints whether the given element is odd or even.

def evenOrodd(array1)
array1.each { |i| 
 if i % 2 == 0
       puts "#{i} is a even number"
     else
       puts "#{i} is a odd number"
     end
      
   }
 end
 
array1 = [1,2,3,5]
evenOrodd(array)


Output
1 is a odd number
2 is a even number
3 is a odd number
5 is a odd number

conclusion

Design patterns help novice software developers to write efficient programs. The novel implementations of a few designs patterns like observer, decorator and iterator in dynamic language like Ruby was discussed above.In the observer pattern the subject notifies any updates in the state to all its dependants (observers).The decorator pattern adds extra features to the already existing class.The iterator helps to access the elements of a collection object individually. The real-world situations where each design pattern can be used were illustrated with respective examples.

References