CSC/ECE 517 Fall 2011/ch4 4h sv: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
Line 66: Line 66:
==Adapter Pattern==
==Adapter Pattern==


An adapter allows classes to work together that normally could not because
An Adapter Design Pattern enables classes with incompatible interfaces to work together. This is achieved as following:
of incompatible interfaces.
 
* It “wraps” its own interface around the interface of a pre-existing
* It “wraps” its own interface around the interface of a pre-existing class.  
class. What does this mean?
* It may also translate data formats from the caller to a form needed by the callee.
* It may also translate data formats from the caller to a form needed by
the callee.


The purpose of an adapter is “to convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.”
The purpose of an adapter is “to convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.”

Revision as of 18:55, 17 October 2011

Design Patterns in Ruby

Introduction

"In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design".

Design Patterns are tools for building software. A Design Pattern is a template to solve a problem which can be used in many different situations. Design Patterns in Object - Oriented Languages help show the relationship between the different classes and objects in the program.

There are different types of design patterns:

  • Singleton Design Pattern, which is used to have only one instance of a class.
  • Adapter Design Pattern, which enables classes with incompatible interfaces to work together.
  • Command Design Pattern, which enables to pass around the code that needs to be executed later.
  • Algorithm Strategy Pattern, which helps choose an algorithm to fulfill a task based on some "parameter" of the situation.
  • Computational Design Patterns, which addresses the concerns related to key computation identification.
  • Execution Design Patterns, which addresses the concerns related to supporting application execution, including strategies in executing streams of tasks and building blocks to support task synchronization.
  • Implementation Strategy Patterns, which addresses the concerns related to implementing source code to support program organization, and the common data structures specific to parallel programming.
  • Structural Design Patterns, which addresses concerns related to high-level structures of applications being developed.

Singleton Pattern

The Singleton design pattern is used to restrict the instantiation of a class to only one instance which is globally available. This is used in situations where a user needs an instance of the class to be available in various parts of the application, being available for logging functionality, communictaion with external systems and database access etc. The Singleton pattern is available as a mixin in the Ruby library. Including it in the code makes the new method private and provides an instance method used to create or access the single instance.

Below is an illustration of the implementation of Singleton Design Pattern in Ruby:

require 'singleton'
class Example
    attr_accessor :val
    include Singleton
end

In the above declaration of a class, including the Singleton module makes the class's new method private. To create an object of that class, the users call the instance method, which returns a singleton instance of the class.

a = Example.instance
b = Example.instance

Here, the instances a and b of the class Example are essentially the same object. When a value of 007 is assigned to a, the value of b is also the same.

a.val = 007
puts b.val
=> 007

Below is an illustration of the Singleton Design Pattern without using the Singleton library. Here, we can observe that the class Logger's new method has been explicitly declared to be private.

class Logger
 def initialize
   @log = File.open("log.txt", "a")
 end
  
 @@instance = Logger.new

 def self.instance
   return @@instance
 end

 def log(msg)
   @log.puts(msg)
 end

 private_class_method :new
end

Logger.instance.log('message 1')

In this code example, inside class Logger we create instance of the very same class Logger and we can access that instance with class method Logger.instance whenever we need to write something to the log file using the instance method "log". In the initialize method we just opened a log file for appending, and at the end of Logger class, we made method "new" private so that we cannot create new instances of class Logger. And, that is Singleton Pattern: only one instance, globally available.

Adapter Pattern

An Adapter Design Pattern enables classes with incompatible interfaces to work together. This is achieved as following:

  • It “wraps” its own interface around the interface of a pre-existing class.
  • It may also translate data formats from the caller to a form needed by the callee.

The purpose of an adapter is “to convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.”

Command Pattern

At times, it is needed to pass around code that needs to be executed later. This is achieved by employing the Command Design Pattern which is used to factor out the action code of a class into its own object. The Command Pattern is implemented using Closures. The Command Pattern does this as follows:

  • A program needs to issue requests to objects. The code that is doing the requesting doesn’t know what the receiver will be, or what operation will be requested.

This is illustrated using the following example:

One example is a check at a restaurant.

  • The waiter/waitress takes an order from a customer and writes it on a check.
  • The check is then queued for the cook, who prepares the food as requested by the customer.
  • The check is later returned to the server, who uses it to bill the customer.

In this example, the check has nothing to do with the menu. In principle, the same checks could be used at any restaurant.

A Command class holds some subset of the following: an object, a method to be applied to the object, and the arguments to be passed when the method is applied. Ruby’s call method then causes the pieces to come together. This Pattern can be implemented using the Proc objects, which is a callable block of code that closes over the variables in scope when it was created. This gives us a concise implementation of Command Pattern.

Below is an illustration of the Command Design Pattern, using Proc Objects:

Another important use of the Command Pattern is to enable the client undo what he has already done, or redo what has been undone by the user. This is done by maintaining a history of the commands executed. As and when the user makes changes, the system creates command after command, executing each command immediately to effect the change. Every undo - able command holds two methods - the execute and the unexecute method. The commands are stored in a list and when the user decides to undo a change, the last command on the list is executed to undo the change. The changes can be undone, by going back the history of commands. The redo is done in the similar way where the the commands are re-executed beginning from the last change that what undone to reapply the changes undone. A simple example of the undo - redo use of a Command Pattern is a Calculator with many undo - redo options.

Strategy Pattern

The strategy pattern (also known as the policy pattern) is a particular software design pattern, whereby algorithms can be selected at runtime. Formally speaking, the strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.[1] For instance, a class that performs validation on incoming data may use a strategy pattern to select a validation algorithm based on the type of data, the source of the data, user choice, and/or other discriminating factors. These factors are not known for each case until run-time, and may require radically different validation to be performed. The validation strategies, encapsulated separately from the validating object, may be used by other validating objects in different areas of the system (or even different systems) without code duplication. The essential requirement in the programming language is the ability to store a reference to some code in a data structure and retrieve it. This can be achieved by mechanisms such as the native function pointer, the first-class function, classes or class instances in object-oriented programming languages, or accessing the language implementation's internal storage of code via reflection.

References

http://designpatternsinruby.com/section01/article.html