CSC/ECE 517 Fall 2007/wiki1b 8 ktrk: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
Line 26: Line 26:


==Strategy Pattern Implementation in Java and Ruby==
==Strategy Pattern Implementation in Java and Ruby==
===Java===
Fighter.java:
package csc517.wiki1b;
public abstract class Fighter {
    private Attack attack;
    public Fighter(){
      setAttack();
    }
    public Attack getAttack() {
      return attack;
    }
    public void setAttack(Attack attack) {
      this.attack = attack;
    }
    protected abstract void setAttack();
    public void fight() {
      getAttack().execute();
    }
}
JudoPlayer.java:
package csc517.wiki1b;
public class JudoPlayer extends Fighter {
    public void setAttack() {
      setAttack(new LegSweep());
    }
}
KickBoxer.java:
package csc517.wiki1b;
public class KickBoxer extends Fighter {
    public void setAttack() {
      setAttack(new RoundhouseKick());
    }
}
Boxer.java:
package csc517.wiki1b;
public class Boxer extends Fighter {
    public void setAttack() {
      setAttack(new Jab());
    }
}
Wrestler.java:
package csc517.wiki1b;
public class Wrestler extends Fighter {
    public void setAttack() {
      setAttack(new ShootIn());
    }
}
Attack.java:
package csc517.wiki1b;
public interface Attack {
    public void execute();
}
RoundhouseKick.java:
package csc517.wiki1b;
public class RoundhouseKick implements Attack {
    public void execute() {
      System.out.println("Roundhouse Kick!");
    }
}
ShootIn.java:
package csc517.wiki1b;
public class ShootIn implements Attack {
    public void execute() {
      System.out.println("Shoot In!");
    }
}
LegSweep.java:
package csc517.wiki1b;
public class LegSweep implements Attack {
    public void execute() {
      System.out.println("Leg Sweep!");
    }
}
Jab.java:
package csc517.wiki1b;
public class Jab implements Attack {
    public void execute() {
      System.out.println("Jab!");
    }
}
Fight.java:
package csc517.wiki1b;
public class Fight {
    public static void main(String[] args) {
      Fighter f1 = new Boxer();
      Fighter f2 = new Wrestler();
      for (int round = 0; round < 3; round++) {
          f1.fight();
          f2.fight();
      }
    }
}
===Ruby===
Fighter.rb:
class Fighter
  attr_accessor :attack
  def initialize(&technique)
    @attack = technique
  end
  def fight
    @attack.call
  end
  def method_missing(method_name)
    puts "I don't know how to #{method_name}"
  end
end
JudoPlayer.rb:
require 'Fighter'
require 'LegSweep'
class JudoPlayer < Fighter
  include LegSweep
  def initialize
    super { leg_sweep }
  end
end
KickBoxer.rb:
require 'Fighter'
require 'RoundhouseKick'
class KickBoxer < Fighter
  include RoundhouseKick
  def initialize
    super { roundhouse_kick }
  end
end
Boxer.rb:
require 'Fighter'
require 'Jab'
class Boxer < Fighter
  include Jab
  def initialize
    super { jab }
  end
end
Wrestler.rb:
require 'Fighter'
require 'ShootIn'
class Wrestler < Fighter
  include ShootIn
  def initialize
    super { shoot_in }
  end
end
RoundhouseKick.rb:
module RoundhouseKick
  def roundhouse_kick
    puts "Roundhouse Kick!"
  end
end
ShootIn.rb:
module ShootIn
  def shoot_in
    puts "Shoot In!"
  end
end
LegSweep.rb:
module LegSweep
  def leg_sweep
    puts "Leg Sweep!"
  end
end
Jab.rb:
module Jab
  def jab
    puts "Jab!"
  end
end
Fight.rb:
require 'Boxer'
require 'Wrestler'
require 'KickBoxer'
require 'JudoPlayer'
rounds = 3
fighters = [ Boxer.new, Wrestler.new ]
rounds.times do
  fighters.each do |fighter|
    fighter.fight
  end
end


==Comparison of Implementations==
==Comparison of Implementations==

Revision as of 03:48, 1 October 2007

Introduction

What is the Strategy Pattern?

The strategy pattern is a proven object oriented design pattern that can be used to solve a common coupling problem often found in software development. Often during the development of compositional classes behaviors and algorithms can become mixed into the class during development without realizing that these behaviors or algorithms may change, become more complex, or additional behaviors may need to be added. These changes could be implemented by extending the class's behavior through inheritance, but over time this could result in an overly complex class hierarchy. The strategy pattern is a design template that can be used to decouple the behavior and algorithms from object being acted upon.

When to Use the Strategy Pattern

In the seminal book on design patterns by the Gang-of-Four (Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides), situations (also labeled "code smells" by Martin Fowler in Refactoring) are described where the strategy design pattern could be used to architect a better solution. These include:

1. A class that exhibits many behaviors

2. A class that uses many variations of an algorithm

3. A class that uses data structures related to a behavior but not the class

4. Many similar classes that differ only in a type of behavior

Advantages of the Strategy Pattern

By decoupling through the use of composition rather than inheritance, several advantages emerge that improve the maintainability and readability of the code.

1. Allows classes to change behavior at runtime or design time

2. Decreases code duplication among classes using variations of the same behavior [1]

3. Behavior is better encapsulated by not being buried in its context [2]

4. A well known design pattern communicates the intent of the code more readily

Similar Patterns

State, Command, and Bridge

Use the state pattern when the state of the object changes with a change in behavior.

Use the bridge pattern when a structural design is needed.

For a discussion of the strategy pattern compared to the state and bridge patterns see Strategy Pattern vs. Bridge Pattern.

Use the command pattern when the invoking object (the context object in the state pattern) does not have knowlege of the recipient object (the behavior in the state pattern). The intermediary command object takes care of dispatching the request to the appropriate object.

Strategy Pattern Implementation in Java and Ruby

Java

Fighter.java:

package csc517.wiki1b;
public abstract class Fighter {
   private Attack attack;
   public Fighter(){
      setAttack();
   }
   public Attack getAttack() {
      return attack;
   }
   public void setAttack(Attack attack) {
      this.attack = attack;
   }
   protected abstract void setAttack();
   public void fight() {
      getAttack().execute();
   }
}

JudoPlayer.java:

package csc517.wiki1b;
public class JudoPlayer extends Fighter {
   public void setAttack() {
      setAttack(new LegSweep());
   }
}

KickBoxer.java:

package csc517.wiki1b;
public class KickBoxer extends Fighter {
   public void setAttack() {
      setAttack(new RoundhouseKick());
   }
}

Boxer.java:

package csc517.wiki1b;
public class Boxer extends Fighter {
   public void setAttack() {
      setAttack(new Jab());
   }
}

Wrestler.java:

package csc517.wiki1b;
public class Wrestler extends Fighter {
   public void setAttack() {
      setAttack(new ShootIn());
   }
}

Attack.java:

package csc517.wiki1b;
public interface Attack {
   public void execute();
}

RoundhouseKick.java:

package csc517.wiki1b;
public class RoundhouseKick implements Attack {
   public void execute() {
      System.out.println("Roundhouse Kick!");
   }
}

ShootIn.java:

package csc517.wiki1b;
public class ShootIn implements Attack {
   public void execute() {
      System.out.println("Shoot In!");
   }
}

LegSweep.java:

package csc517.wiki1b;
public class LegSweep implements Attack {
   public void execute() {
      System.out.println("Leg Sweep!");
   }
}

Jab.java:

package csc517.wiki1b;
public class Jab implements Attack {
   public void execute() {
      System.out.println("Jab!");
   }
}

Fight.java:

package csc517.wiki1b;
public class Fight {
   public static void main(String[] args) {
      Fighter f1 = new Boxer();
      Fighter f2 = new Wrestler();
      for (int round = 0; round < 3; round++) {
         f1.fight();
         f2.fight();
      }
   }
}

Ruby

Fighter.rb:

class Fighter
  attr_accessor :attack
  def initialize(&technique)
    @attack = technique
  end
  def fight
    @attack.call
  end
  def method_missing(method_name)
    puts "I don't know how to #{method_name}"
  end
end

JudoPlayer.rb:

require 'Fighter'
require 'LegSweep'
class JudoPlayer < Fighter
  include LegSweep
  def initialize
    super { leg_sweep }
  end
end

KickBoxer.rb:

require 'Fighter'
require 'RoundhouseKick'
class KickBoxer < Fighter
  include RoundhouseKick
  def initialize
    super { roundhouse_kick }
  end
end

Boxer.rb:

require 'Fighter'
require 'Jab'
class Boxer < Fighter
  include Jab
  def initialize
    super { jab }
  end
end

Wrestler.rb:

require 'Fighter'
require 'ShootIn'
class Wrestler < Fighter
  include ShootIn
  def initialize
    super { shoot_in }
  end
end

RoundhouseKick.rb:

module RoundhouseKick
  def roundhouse_kick
    puts "Roundhouse Kick!"
  end
end

ShootIn.rb:

module ShootIn
  def shoot_in
    puts "Shoot In!"
  end
end

LegSweep.rb:

module LegSweep
  def leg_sweep
    puts "Leg Sweep!"
  end
end

Jab.rb:

module Jab
  def jab
    puts "Jab!"
  end
end

Fight.rb:

require 'Boxer'
require 'Wrestler'
require 'KickBoxer'
require 'JudoPlayer'
rounds = 3
fighters = [ Boxer.new, Wrestler.new ]
rounds.times do
  fighters.each do |fighter|
    fighter.fight
  end
end

Comparison of Implementations

References

Design Patterns, Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Addison-Wesley Pulishing, 1995

Refactoring: Improving the Design of Existing Code, Martin Fowler, Addison-Wesley Publishing, 1999

http://en.wikipedia.org/wiki/Strategy_pattern