edgards
edgards

Reputation: 99

Why do we use Strategy Pattern?

I just learned what the Strategy pattern really is from the Internet. But I wondered how it can improve my code. For example, i have the following codes found in the Internet like this. This is the Superclass named Animal:

abstract public class Animal {
    private String name;
    private int weight;
    private String sound;

    public void setName(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }

    public void setWeight(int weight){
        if(weight > 0){
            this.weight = weight;
        }else {
            System.out.println("Weight must be bigger than 0");
        }
    }

    public int getWeight(){
        return weight;
    }

    public void setSound(String sound){
        this.sound = sound;
    }
    public String getSound(){
        return sound;
    }

    public void specialMethod(){
        System.out.println("Ok");
    }
}

This is the subclass named Dog:

public class Dog extends Animal {
    public void digHole(){
        System.out.println("Dig a hole");
    }

    public Dog(){
        super();
        setSound("bark");
    }

    public void testSuper(Animal obj){
        System.out.println(obj.getName());
    }
}

In the tutorial, it said that if we want to add flying ability so that I can check whether dog can fly or not. Adding the code directly like this one is bad as shown in the code below.

The Superclass Animal with an added flying ability method

abstract public class Animal {
    private String name;
    private int weight;
    private String sound;

    // Add fly method to the superclass which is a bad idea 
    public String fly(){
        return " I am flying ";
    }

    public void setName(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }

    public void setWeight(int weight){
        if(weight > 0){
            this.weight = weight;
        }else {
            System.out.println("Weight must be bigger than 0");
        }
    }

    public int getWeight(){
        return weight;
    }

    public void setSound(String sound){
        this.sound = sound;
    }

    public String getSound(){
        return sound;
    }

    public void specialMethod(){
        System.out.println("Ok");
    }
}

Using the Strategy pattern, we can create interface named Flys with the method fly, allowing any subclass to implement the method, thus as shown in the tutorial, I created Interface named Flys with 2 subclasses implementing the interface:

public interface Flys {
    String fly();
}

class ItFlys implements Flys{
    public String fly(){
        return "Flying high";
    }
}

class CantFly implements Flys{
    public String fly(){
        return "I can't fly";
    }
}

Once I made the interface, I can refactor the class Animal,

abstract public class Animal {
    private String name;
    private int weight;
    private String sound;
    Flys flyingType; // Add an object of the interface to the superclass 

    public String tryToFly(){ // add a new method tryToFly
        return flyingType.fly();
    }

    // Adding another method named setFlyingAbility 
    public void setFlyingAbility(Flys newFlyType){
        flyingType = newFlyType;
    }

    public void setName(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }

    public void setWeight(int weight){
        if(weight > 0){
            this.weight = weight;
        }else {
            System.out.println("Weight must be bigger than 0");
        }
    }

    public int getWeight(){
        return weight;
    }

    public void setSound(String sound){
        this.sound = sound;
    }

    public String getSound(){
        return sound;
    }

    public void specialMethod(){
        System.out.println("Ok");
    }
}

Now, in my Dog subclass, I simply add another code

public class Dog extends Animal {
    public Dog(){
        super();
        setSound("bark");
        flyingType = new CantFly(); // I set flyingType object 
    }

    public void digHole(){
        System.out.println("Dig a hole");
    }

    public void testSuper(Animal obj){
        System.out.println(obj.getName());
    }
}

The final class is where I can execute all codes, checking whether my Dog class can fly or not.

public class AnimalPlay {
    public static void main(String args[]){
        Animal sparky = new Dog();
        Animal tweety = new Bird();
        System.out.println("Dog " + sparky.tryToFly()); // the result is I can't fly 
        System.out.println("Bird " + tweety.tryToFly()); // the result is I am flying 
        sparky.setFlyingAbility(new ItFlys());
        System.out.println("Dog " + sparky.tryToFly()); // the result is I am flying 
    }
}

My question is, what about If I still add the fly() method the traditional way, it gives the same result, doesn't it?

Adding the fly() method to the superclass so I can override the fly() method in my Dog class, but this is not a good idea.

abstract public class Animal {
    private String name;
    private int weight;
    private String sound;

    // Add fly method to the superclass which is a bad idea 
    public String fly(){
        return " I am flying ";
    }

    public void setName(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }

    public void setWeight(int weight){
        if(weight > 0){
            this.weight = weight;
        }else {
            System.out.println("Weight must be bigger than 0");
        }
    }

    public int getWeight(){
        return weight;
    }

    public void setSound(String sound){
        this.sound = sound;
    }
    public String getSound(){
        return sound;
    }

    public void specialMethod(){
        System.out.println("Ok");
    }
}

Upvotes: 1

Views: 1184

Answers (2)

Dzianis Yafimau
Dzianis Yafimau

Reputation: 2016

My question is, what about If I still add the fly() method the traditional way, it gives the same result, doesn't it?

The answer is 'NO'.

  1. Strategy pattern allows you to move behavior into separate class which is good by SOLID principle 'S' - single responsibility. Image that you need to learn robot or human to 'bark' - you don't need to make them inherit animal base class. And you also don't need to implement barking in each class.
  2. Having all properties in base class is also not good as it is against SOLID 'L' - Liskou substitution. What if monkey don't need to bark which is implemented in base animal class?
  3. Strategy pattern allows you to design code accordingly to SOLID 'I' - Interface segregation - just make IAnimalAction interface make many implementations of barking and assign IAnimalAction property to desired animal classes (as property or as one more interface to implement)
  4. Strategy also helps with SOLID 'D' - you can inject desired animal strategy (barking, flying) without having each animal even know about it

We can continue and find other bonuses. But you can see a picture

Good luck!

Upvotes: 3

ThePolisher
ThePolisher

Reputation: 379

I am not sure which came first, but the Strategy pattern like any other behavioral pattern is a specific instance of the open close principle. In general you want to change the behavior of an object without having to change it's code. This has a profound consequences in terms of extendability, maintainability and coherence.

Upvotes: 1

Related Questions