设计模式之策略模式

我们先从一个经典的例子说起,假如现在我应聘去一家公司上班,第一天老板让我设计一个鸭子的类,

public abstract class Duck {

    public void quack(){            //叫唤
        System.out.println("gua...");
    }
    
    public void swim(){                //游泳
        System.out.println("swimming...");
    }
    
    public  abstract void display();//外观
    
}

考虑到每个鸭子的外观都不同,所以把外观定为抽象类,

过了两天,老板决定给鸭子增加一个飞行的方法,that's so easy!,在Duck类里面加上就行了,

public abstract class Duck {

    public void quack(){            //叫唤
        System.out.println("gua...");
    }
    
    public void swim(){                //游泳
        System.out.println("swimming...");
    }
    
    public void fly() {          //飞行
        System.out.println("fly...");
    }
    public  abstract void display();//外观
    
}

但是这样做有个问题,有的鸭子不会飞,比如橡皮鸭之类的东东,如果继承这个类的话,也会飞起来,这该肿么办呢?

可以让不会飞的鸭子在继承Duck类时,覆盖fly()方法,例如:

public class RubberDuck extends Duck {

    @Override
    public void display() {
        System.out.println("I am a rubberDuck");
    }

       @Override
    public void fly() {     
        
    }
}

有的鸭子即不会飞,也不会叫,也可以通过覆盖来完成,比如诱饵鸭

public class DecoyDuck extends Duck {

    @Override
    public void display() {
        System.out.println("I am a decoyDuck");
    }

    @Override
    public void quack() {
        
    }

    @Override
    public void fly() {
        
    }    
}

但鸭子种类太多,方法也各不相同,每种鸭子都要写一些无用的代码来覆盖父类的方法,实在麻烦,所以我想到了接口,用接口就可以不用写那些无用的代码

//定义两个接口
public interface Flyable {  
    public void fly();
}
public interface Quackable {
    public void quack();  
}
//Duck类可以改写为
public abstract class Duck {

    public void swim(){    //游泳
        System.out.println("swimming...");
    }
    public abstract void display();//外观

}
//橡皮鸭就可以不用写fly()这种无用的代码
public class RubberDuck extends Duck implements Quackable{

    @Override
    public void display() {
        System.out.println("I am a rubberDuck");
    }

    public void quack() {
        System.out.println("RubberDuck's quack...");
    }    
}

这又产生一个问题,那就是代码无法像原来继承那样复用了,比如现在有100种各式各样的鸭子,其中50种鸭子的quack()方法一样,如果用上面的方法,就要写50次一模一样的quack(),也是麻烦,这里涉及到了一条重要的规则:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起

现在我们分开“变化和不会变化的部分”,建立两组类(完全远离Duck类),一组是和“fly”相关的,一组和“quack”相关,每组类实现各自的动作

//定义两个接口
public interface Flyable {  
    public void fly();
}
public interface Quackable {
    public void quack();  
}
//Duck类可以改写为
public abstract class Duck {

    Flyable fly;
    Quackable quack;
    public void swim(){    //游泳
        System.out.println("swimming...");
    }
    public abstract void display();//外观
}

public class FlyWithWings implements Flyable{
    public void  fly(){
     //实现了所有有翅膀的鸭子飞行行为。
   }
 }
public class FlyNoWay implements Flyable{
    public void  fly(){
      //什么都不做,不会飞
    }
 }   

public class Quack implements Quackable{
    public void quack(){
      //实现呱呱叫的鸭子
  }
}
 
public class Squeak implements Quackable{
    public void quack(){
      //实现吱吱叫的鸭子 
  }
}
 
public class MuteQuack implements Quackable{
    public void quack(){
      //什么都不做,不会叫
  }
}


//橡皮鸭
public class RubberDuck extends Duck {

    public RubberDuck() {
        quack = new MuteQuack();
        fly   = new FlyNoWay();
    }
    @Override
    public void display() {
        System.out.println("I am a rubberDuck");
    }

}

这样做就比较容易扩展了,

原文地址:https://www.cnblogs.com/fengz/p/6747566.html