CSC/ECE 517 Fall 2011/ch4 4h sv: Difference between revisions
Line 2: | Line 2: | ||
==Introduction== | ==Introduction== | ||
''"In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design".'' | ''"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 ways. | Design Patterns are tools for building software. A Design Pattern is a template to solve a problem which can be used in many different ways. | ||
__TOC__ | __TOC__ |
Revision as of 16: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 ways.
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:
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.
require 'singleton' class Example include Singleton attr_accessor :val end r = Registry.new #throws a NoMethodError r = Registry.instance r.val = 5 s = Registry.instance puts s.val >> s.val = 6 puts r.val >> s.dup >>
Adapter Pattern
An adapter allows classes to work together that normally could not because of incompatible interfaces.
- It “wraps” its own interface around the interface of a pre-existing
class. What does this mean?
- 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 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.
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.
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.