设计模式之策略模式
同样地,个人理解,如有错误或说的不明白的地方,请一定不吝指出,不胜感激。
首先我们明确一下概念,然后会列一个例子;如果概念不明白的同学可以先看例子,然后回味概念。
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通信开销。
下一篇: select/poll/epoll