目的:将对象和行为解耦。由继承得来的行为,灵活性不够,行为是写死在类中的。如果需要修改,
只能修改原来的类。如果修改超类,则所有子类都受影响。如果修改子类,那么子类中会出现大量
重复代码。比如有十个子类,它们的行为与超类行为不同,则要修改十个子类。问题是,这十个子
类的行为是一致的,却无法将行为重用。将行为抽离出来,则可以达到共用的目的。
-
只需要在对象中包含一个行为对象,调用行为对象的方法来完成对应行为即可。
-
行为对象要实现特定行为的接口。
比如一个Person对象,有吃饭,睡觉的行为。当然,你可以说人的吃和睡,能有什么差别。是的,大
部分人都是一样的。但是,有的人,就细嚼慢咽,有的人,则狼吞虎咽,对于一种行为来说,这确实是
有差别的。有的人睡觉很安静,有的人睡觉打呼噜,还的的人睡觉睁着眼睛,这也是差别。具体什么样
的差别算差别,还是业务逻辑说了算。
这时,最基本也是最直接的方式,就是在Person类中实现默认的,普遍的吃饭和睡觉方法。然后子类中
那些特别的人,去覆盖对应的方法。这时候,问题来了,有的人睡觉很安静,吃饭狼吞虎咽;有的人睡觉
很安静,吃饭细嚼慢咽;有的人睡觉打呼噜,吃饭狼吞虎咽。。。。对于这些拥有不同行为的人,要
创建它们的实例,就得根据行为不同,组合出各种不同的类,类爆炸来了。
public class Person {
public void sleep() {
System.out.println("普通人睡觉");
}
public void eat() {
System.out.println("普通人吃饭");
}
}
class Snorer extends Person{
public void sleep() {
System.out.println("呼噜。。。呼噜。。。");
}
}
class Huger extends Person{
public void eat() {
System.out.println("狼吞虎咽");
}
}
// 更多形形色色的组合
策略模式很好的解决了这个问题。
将睡觉,吃饭这些行为分离出去,不在是Person类的方法。而是单独的行为对象。行为对象只需要实现
行为接口。睡觉这个行为对象,实现了睡觉行为接口,假设为: interface Sleep 这个接口中,只有
一个方法, void sleep(); 很明显,行为对象实现此接口,只需要实现sleep方法即可。吃饭行为对象
也是一样。
现在行为对象有了,怎么和Person对象联系起来呢?
需要在Person类内部创建一个实例变量: Sleep sleepBehavior;
将以前硬编码在Person类内部的 sleep,eat方法做下修改。
interface Sleep{
void sleep();
}
interface Eat{
void eat();
}
public class SnorerSleep implements Sleep{
System.out.println("呼噜。。。呼噜。。。");
}
public class HugerEat implements Eat{
System.out.println("狼吞虎咽");
}
public abstract class Person{
Sleep sleepBehavior;
Eat eatBehavior;
public void sleep(){
sleepBehavior.sleep();
}
public void eat(){
eatBehavior.eat();
}
}
public class Snorer extends Person{
public Snorer(){
this.sleepBehavior = new SnorerSleep();
}
}
new Snorer().sleep(); // 呼噜。。。呼噜。。。
如果需要在运行时,动态的改变Person对象的行为,可以添加 sleepBehavior 和 eatBehavior 的setter
,调用之后,实例的行为就会发生变化。
这样,行为得到了复用,并且和对象解耦了。是不是更容易维护了?
缺点:
- 会产生很多策略类,但是相对原来的模式,要好很多。
- 需要了解所有的策略,才能作出正确的选择。但是,代码是咱们写的,这不是什么问题。有文档,更简单。