欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设计模式之策略模式

程序员文章站 2022-06-13 12:58:33
...

同样地,个人理解,如有错误或说的不明白的地方,请一定不吝指出,不胜感激。

首先我们明确一下概念,然后会列一个例子;如果概念不明白的同学可以先看例子,然后回味概念。

1.概念

策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

2.例子

产品经理安排大白设计一个游戏,这个游戏包括如下角色:国王、王后、巨怪以及骑士。每个人都有自己的武器,国王拥有宝剑、王后拥有匕首、骑士拥有弓箭、巨怪拥有斧头。每种武器的使用方式不一样,因此每个人的攻击方式自然就不一样。

大白一想,这还不简单?十分钟就设计了出来:

version1:

设计模式之策略模式

大白成功写好代码并上线,运行正常。几天后,产品经理找到大白:“我想给骑士和国王加上骑马的操作。”

这时,大白想了想:“我是应该把rideHorse()方法加到Character中还是给骑士和国王各加一个呢?”如果加到Character类中,那么每个子类都会有一个rideHorse()方法,包括王后和巨怪!如果给骑士和国王各加一个,那么这两个类中的rideHorse()方法将会一样!rideHorse()方法无法复用!

这时,大白想起了一条著名的设计原则:针对接口编程,而不是针对实现编程。

“有了!我创建一个ride的接口,让骑士和国王都实现这个接口就可以了!”大白很激动,立马完成了设计:

version2:

设计模式之策略模式

这时,大白的同事指出了问题:如果产品经理又让王后可以骑马怎么办?这样代码不还是不能复用吗?

在同事的帮助下,大白学习了策略设计模式,最终完成了代码设计:

version3:

设计模式之策略模式

父类代码:

public abstract class Character {
    Ride ride;
    abstract void attack();
    public void ride(){
        ride.ride();
    }
}

接口:

public interface Ride {
    void ride();
}

接口的实现类:

public class RideHorse implements Ride {
    @Override
    public void ride() {
        System.out.println("骑马");
    }
}
public class RideCow implements Ride {
    @Override
    public void ride() {
        System.out.println("骑牛");
    }
}

国王:

public class King extends Character implements Ride{
    King(Ride ride){
        this.ride = ride;
    }
    @Override
    void attack() {
        System.out.println("用宝剑刺");
    }
}

王后:

public class Queen extends Character{
    @Override
    void attack() {
        System.out.println("用匕首刺");
    }
}

骑士:

public class Knight extends Character implements Ride{
    Knight(Ride ride){
        this.ride = ride;
    }
    @Override
    void attack() {
        System.out.println("射箭");
    }
}

巨怪:

public class Troll extends Character{
    @Override
    void attack() {
        System.out.println("用斧头砍");
    }
}

大功告成!我们来测试一下:

public static void main(String[] args) {
        Character knight = new Knight(new RideHorse());
        knight.ride();
}

我们可以给国王和骑士添加setRide()方法,这样就可以在运行时决定到底是“骑马”还是“骑牛”了。

通过测试代码,我们可以看到策略模式并不是完美的:首先,客户端需要知道所有的策略类,并在调用的时候自行决定使用哪一个策略类,这时候我们可以通过结合工厂模式来解决这个问题。除此之外,策略模式产生了很多的策略类,以及增加了Strategy与Context通信开销。