一、什么是策略模式?
策略模式:将可变的部分从程序中抽象分离成算法接口,在该接口下分别封装一系列算法实现。
二、光荣与梦想—鸭子应用:策略模式的实现
1、模拟应用背景:
鸭子应用代码如下:
package com.sfd.duck;
/**
* 抽象类所有种类的鸭子都要继承的类
* @author sfd
*
*/
public abstract class Duck {
/**
* 鸭子发出声音
* 通过行为,由超类实现
*/
public void quack(){
System.out.println("嘎嘎嘎");
}
/**
* 用来展示鸭子
*/
public abstract void display();
}
列举出两个实例:绿脖鸭和红头鸭
package com.sfd.duck;
//绿脖鸭
public class MallardDuck extends Duck{
public MallardDuck(){
super();
}
@Override
public void display() {
System.out.println("我的脖子是绿色的");
}
}
//红头鸭
public class RedHeadDuck extends Duck{
public RedHeadDuck(){
super();
}
@Override
public void display() {
System.out.println("我的头是红色的");
}
}
2.让鸭子飞起来
1.方案一:继承
在父类中提供实现方法,子类通过继承获得父类的中的飞行行为;
public void fly(){
System.out.println("用翅膀飞行");
}
优点:简(cu)单(bao)易用,已有的应用可以快速添加飞行的能力。
缺点:不具有灵活性,对未来的变更支持差(所有Duck类的子类都拥有了用翅膀飞行的能力包括玩具鸭子,显然是不对的)需要通过在子类中覆写飞行的方法以提供新的飞行行为。这很容易造成错误(粗心的程序员忘记覆写)。
这种方案不建议使用
2.方案2:抽象方法
在父类中提供抽象方法,强迫子类实现自己的飞行行为:
public abstract void fly();
优点:足够灵活!再也不会忘记覆写代码了,玩具鸭也不会飞到天上去了;
缺点:代码量太大,每一个子类都要实现飞行方法,尽管实现方法的代码大多数相同;代码重复,没有复用代码。万一再有个bug。。。
这种方案也不建议使用
继承是重用代码的利器,但是继承并不总是最好的工具。
3.最优方案:组合
组合合优先于继承,多用组合,少用继承(Favor composition over inheritance)
什么是组合:在类中增加一个私有域,引用一个已有的类的实例,通过调用引用实例的方法从而获得新的功能,这种设计被称作组合(复合)。
将飞行行为抽象陈接口,在父类中持有该接口,并由该心口代理飞行行为。
优点:足够灵活,复用代码,更易于维护。
缺点:。。。
代码实现:
1.飞行策略接口:
package com.sfd.duck;
public interface FlyingStragety {
void performFly();
}
2.更改所有鸭子的父类Duck类,增加一个FlyingStragety 成员变量只想具体的飞行策略;
package com.sfd.duck;
/**
* 抽象类所有种类的鸭子都要继承的类
* @author sfd
*
*/
public abstract class Duck {
private FlyingStragety flyingStragety;
public void setFlyingStragety(FlyingStragety flyingStragety) {
this.flyingStragety = flyingStragety;
}
/**
* 鸭子发出声音
* 通过行为,由超类实现
*/
public void quack(){
System.out.println("嘎嘎嘎");
}
/**
* 用来展示鸭子
*/
public abstract void display();
public void fly(){
flyingStragety.performFly();
}
}
3.两个鸭子实现类的更改:
package com.sfd.duck;
import com.sfd.duck.impl.FlyWithWin;
public class MallardDuck extends Duck{
public MallardDuck(){
super();
super.setFlyingStragety(new FlyWithWin());
}
@Override
public void display() {
System.out.println("我的脖子是绿色的");
}
}
package com.sfd.duck;
import com.sfd.duck.impl.FlyWithWin;
public class RedHeadDuck extends Duck{
public RedHeadDuck(){
super();
super.setFlyingStragety(new FlyWithWin());
}
@Override
public void display() {
System.out.println("我的头是红色的");
}
}
这时我们需求有了变动,现在我们需要增加一中不会飞的塑料鸭,这时我们完成起来就十分方便了:
只需要增加一个Duck的实现类和这个新类拥有的新的飞行策略可以了,原先的代码完全不用更改:
新的飞行策略:
package com.sfd.duck.impl;
import com.sfd.duck.FlyingStragety;
public class FlyNoWay implements FlyingStragety {
@Override
public void performFly() {
System.out.println("我不会飞行");
}
}
新类型鸭子—塑料鸭子(不会飞)
package com.sfd.duck;
import com.sfd.duck.impl.FlyNoWay;
public class RubberDuck extends Duck{
public RubberDuck(){
super();
super.setFlyingStragety(new FlyNoWay());
}
public void quack() {
System.out.println("嘎~嘎~嘎~");
}
@Override
public void display() {
System.out.println("我是一直橡胶鸭");
}
}
测试代码:
package com.sfd.duck;
public class Test {
public static void main(String[] args) {
Duck duck=null;
// duck=new MallardDuck();
// duck=new RedHeadDuck();
duck=new RubberDuck();
duck.display();
duck.quack();
duck.fly();
}
}
这样用策略模式实现的飞行方法就完成了;其实我们的代码还不是很完善的,仔细观察胡发现鸭子叫的方法quack()其实也可以用策略模式来完成,这就叫给大家啦!!!!