Refractoring to Patterns by zhangyun


									Refactoring to Patterns

         Ravindra Chilaka
   Extreme Programming Seminar
            XP 2004 b
   Patterns Introduction.
    - What is a pattern?
    - What makes a pattern?
    - Why use pattern?
   Refactoring.
    - Refactoring.
    - Why Refactoring to patterns?
    - When to Refractor?
    - Example : Switch Statement.
    - The Refactoring Environment.
   Examples of Refactoring to Patterns.
    - Extract Adapter.
    - The Template Method.           (continued..)
    - Encapsulate Classes with Factory.
    - Encapsulate Composite with Builder.
    - Move Embellishment to Decorator.
    - Replace Conditional Logic with Stratergy.
    - Replace Hard-Coded Notifications with Observer.
   Summary.
   Questions ??
            Patterns Introduction
What is a Pattern: (Definition)
 Each pattern describes a problem which occurs over and
  over again in our environment, and then describes the core of
  the solution to that problem, in such a way that you can use
  this solution a million times over, without ever doing it the
  same way twice. (C. Alexander, “The Timeless Way of Building”,
   „A pattern is a named nugget of insight that conveys the
    essence of a proven solution to a recurring problem within a
    certain context amidst competing concerns.“ (Brad
    Applenton, „Patterns and Software : Essential Concepts and
          Patterns Introduction
   Patterns describe common ways of doing things.
   They are collected by people who spot repeating themes in
   They take each theme and describe it so that others can use
   They capture the static and dynamic structures and
    collaborations of successful solutions to problems that arise
    when building applications in a particular domain.
   A Pattern is much more than a Model.
   Design Patterns describe good solutions to common (or at
    least, not extremely rare) design problems:

       Design Patterns are always specified in UML.
       Model-View-Controller is a very common Design Pattern.
       Design Patterns describe the higher-level organization of
        solutions to common problems.
          Patterns Introduction
   What makes a pattern?

   Solve a problem (It must be useful)

   Have a Context (Where it can be used)

   Recur (Must be relevant in other situations)

   Teach (provide sufficient understanding to tailor the solution)

   Name (To refer Consistently).
          Patterns Introduction
   Why use Patterns?

    Patterns help you learn from other‟s successes, instead of
    your own failures (Mark Johnson (cited by B. Eckel))

   An additional layer of abstraction
      separate things that change from things that stay the
      distilling out common factors between a family of similar
      similar to design

   Insightful and clever way to solve a particular class of
       most general and flexible solution
   Refactoring is rearranging existing code while maintaining the
    same functionality
      Refactoring is usually done in terms of applying some
       Design Pattern
   Refactoring is restructuring code in a series of small,
    semantics-preserving transformations (i.e. the code keeps
    working) in order to make the code easier to maintain and
      Refactoring often modifies or introduces Design Patterns
   Refactoring is not just any old restructuring
      You need to keep the code working
      You need small steps that preserve semantics
      You need to have unit tests to prove the code works
   There are numerous well-known refactoring techniques
      You should be at least somewhat familiar with these
       before inventing your own
   Why Refactoring to Patterns ?

   To reduce or remove Duplication.
   Simplifying the unsimple.
   Make our code better at its intention.
   When to Refactor ?

   You should refactor:
      Any time that you see a better way to do things
       1. “Better” means making the code easier to understand
          and to modify in the future
      You can do so without breaking the code
       1. Unit tests are essential for this
   You should not refactor:
      Stable code (code that won‟t ever need to change)
      Someone else‟s code
       1. Unless you‟ve inherited it (and now it‟s yours)
Example : switch statements
   switch statements are very rare in properly designed object-
    oriented code.
       Therefore, a switch statement is a simple and easily
        detected “bad smell”.
       Of course, not all uses of switch are bad.
       A switch statement should not be used to distinguish
        between various kinds of object.
   There are several well-defined refactorings for this case
       The simplest is the creation of subclasses.
          Example, continued
   class Animal {
      final int MAMMAL = 0, BIRD = 1, REPTILE = 2;
      int myKind; // set in constructor
      String getSkin() {
        switch (myKind) {
          case MAMMAL: return "hair";
          case BIRD: return "feathers";
          case REPTILE: return "scales";
          default: return "integument";
           Example, continued
   class Animal {
       String getSkin() { return "integument"; }
    class Mammal extends Animal {
       String getSkin() { return "hair"; }
    class Bird extends Animal {
       String getSkin() { return "feathers"; }
    class Reptile extends Animal {
       String getSkin() { return "scales"; }
How is this an improvement?
   Adding a new animal type, such as Amphibian, does not
    require revising and recompiling existing code.
   Mammals, birds, and reptiles are likely to differ in other ways,
    and we‟ve already separated them out (so we won‟t need
    more switch statements).
   We‟ve gotten rid of the flags we needed to tell one kind of
    animal from another.
   Basically, we‟re now using Objects the way they were meant
    to be used.
                    JUnit tests
   As we refactor, we need to run JUnit tests to ensure that we
    haven‟t introduced errors
   public void testGetSkin() {
        assertEquals("hair", myMammal.getSkin());
        assertEquals("feathers", myBird.getSkin());
        assertEquals("scales", myReptile.getSkin());
        assertEquals("integument", myAnimal.getSkin());
   This should work equally well with either implementation
   The setUp() method of the test fixture may need to be
The Refactoring Environment
   Traditional software engineering is modeled after traditional
    engineering practices (= design first, then code)
   Assumptions:
       The desired end product can be determined in advance
       Workers of a given type (plumbers, electricians, etc.) are
   “Agile” software engineering is based on different
       Requirements (and therefore design) change as users
        become acquainted with the software
       Programmers are professionals with varying skills and
       Programmers are in the best position for making design
   Refactoring is fundamental to agile programming
       Refactoring is sometimes necessary in a traditional
        process, when the design is found to be flawed
    Examples of Refactoring to
   Extract Adapter
   The Template Method
   Encapsulate Classes with Factory
   Encapsulate Composite with Builder
   Move Embellishment to Decorator
   Replace Conditional Logic with Strategy
   Replace Hard-Coded Notifications with Observer
           Examples of Refactoring to
   Extract Adapter:

    One Class adapts
    multiple versions of
    component, library,
    API or other Entity.

   Solution:

    Extract an Adapter for
    a single version of the
    component , library, API
    or other Entity.
    Examples of Refactoring to
   The Template Method:

   Template Methods lead to an inverted control structure
        A superclass calls methods in its subclass
    Template methods are so fundamental that they can be found
    in almost every abstract class
   Template Method uses inheritance
   A similar pattern, Strategy Pattern, uses delegation rather than
    Examples of Refactoring to
   Example : Big fish and little
   The scenario: “big fish” and
    “little fish” move around in an
          Fish         move       about
          A big fish can move to
           where a little fish is (and
           eat it)
          A little fish will not move to
           where a big fish is
    Examples of Refactoring to
   General outline of the method:
       public void move() {
          choose a random direction;           // same for both
          find the location in that direction; // same for both
          check if it’s ok to move there;      // different
          if it’s ok, make the move;          // same for both
   Solution:
       Extract the check on whether it‟s ok to move
       In the Fish class, put the actual (template) move() method
       Create an abstract okToMove() method in the Fish class
       Implement okToMove() in each subclass
         Examples of Refactoring to
                        Fish                       Note how this works:
                                                    When a BigFish tries
                                                    to move, it uses the
                                                    move() method in Fish
                                                   But      the     move()
             BigFish          LittleFish            method in Fish uses
             move()            move()               the    okToMove(locn)
                                                    method in BigFish
                                                   And      similarly  for

       BigFish                        BigFish
okToMove(locn):boolean     okToMove(locn):boolean
         Examples of Refactoring to
   Encapsulates Classes
    with Factory:
    Clients directly
    instantiate classes that
    reside in one package
    and implement a
    common interface.
   Solution:
    Make the class
    constructors non-public
    and let clients creates
    instances of them using
    a factory.
             Types of Refactoring to
   Encapsulate
    Composite with

    Building a composite is
    repititive , complicated
    or error-prone.

   Solution:

    Simplify the build by
    letting the Builder
    handles the details.
       Examples of Refactoring to
   Embellishment
    to Decorator:

    Code Provides
    an embellishment
    to a class„ core

   Solution:

    Move the
    code to a
          Examples of Refactoring to
   Replace
    Conditional Logic
    with Stratergy:

    conditional logic in a
    method controls
    which of several
    variants of a
    calculation are
   Solution:
    create a Stratergy
    for each variant and
    make the method
    delegate the
    caliculation to a
    single stratergy.
         Examples of Refactoring to
   Replace Hard-
    Coded Notifications
    with Observer:
    Subclasses are
    hardcoded to notify a
    single instance of
    another class.
   Solution:
    Remove the
    subclasses by
    making their
    superclass capable
    of notifying one or
    more instances of
    any classes that
    implement a
    observable interface.
   Patterns describe common ways of doing things. They are
    collected by people who spot repeating themes in designs.
   We should refactor any time we detect a “bad smell” in the
    code. Refactoring makes code easier to understand, maintain
    and modify.
   Various Refactoring techniques to the patterns can be applied
    to the real-world problems depending up on the application
    criteria and usage of the system. (For e.g.: Observer ,Strategy
    and Template Patterns, etc. are most commonly used).
Questions ??


To top