使用设计模式最好的方式:把设计模式装进脑袋里面,然后在你的设计和已有的应用中,寻找何处可以使用它们。
设计模式是一种前人踩过的坑,之后总结下来的编程经验,也就是说这样做通常比较好。我们学习这种经验,以便在我们以后的项目中避免很多问题。
应用场景
举个例子,一个鸭子类。
原来有一些行为,现在要加入飞行的方法。那么怎么做才是最好的解决方法呢?
注意,并不是所有的鸭子都能飞。
所以直接在父类里面加进去飞行方法是有问题的。
这个飞行动作 是可变的,并不是每种都有的。
- 涉及到维护的时候,为了复用而使用继承,结局并不好。
- 对超类进行局部修改,影响层面是全局的。
如果使用接口,那么虽然解决了只有会飞的鸭子才能飞的问题,但是呢,却造成了原来所有的实现都要修改和大量的代码冗余。
解决办法
每次新的需求来了,需要改变的部分,就是要封装起来的部分。
核心思想:把会变化的部分取出并封装起来 ,以便以后可以轻易地改动或者扩展此部分,而不影响其他不需要变化的部分。
把飞行的行为作为一个借口,依附于超级鸭子父类
鸭子的子类使用接口所表示的行为,不会绑死在鸭子的子类里面。
下面是全部代码
首先是 duck类
public abstract class Duck {
public Duck(){
};
FlyBehavior flyBehavior;
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void performFly(){
flyBehavior.fly();
}
public void swim(){
System.out.println("所有鸭子都可以游泳");
}
}
接下来是飞行接口。
public interface FlyBehavior {
public void fly();
}
实现飞行借口的类
public class FlyWithNoWay implements FlyBehavior{
@Override
public void fly() {
System.out.println("我不会飞!");
}
}
另一个
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("翅膀飞");
}
}
最后我们真正用到的鸭子
public class MallardDuck extends Duck {
public MallardDuck() {
flyBehavior=new FlyWithWings();
}
}
测试类
public class TestFly {
public static void main(String[] args) {
Duck duck=new MallardDuck();
duck.performFly();
duck.setFlyBehavior(new FlyWithNoWay());
duck.performFly();
}
}
运行结果
- 翅膀飞
- 我不会飞!
维护以及优点
假如说以后加入一个喷气鸭子,怎么办呢?
public class FlywithRocket implements FlyBehavior {
@Override
public void fly() {
System.out.println("喷气飞");
}
}
public class TestFly {
public static void main(String[] args) {
Duck duck=new MallardDuck();
duck.performFly();
duck.setFlyBehavior(new FlywithRocket());//喷气飞
duck.performFly();
}
}
那么假如要加入一个新的行为,比如说eat ,这个行为至少橡皮鸭子就是不能吃的。
所以首先要新写一个eat的接口。
public interface EatBehavior {
public void eat();
}
实现接口的具体吃法
public class EatWithGlass implements EatBehavior {
@Override
public void eat() {
System.out.println("吃草");
}
}
public class EatWithNothing implements EatBehavior {
@Override
public void eat() {
System.out.println("什么都不吃");
}
}
接下来修改原来的DUCK类
public abstract class Duck {
public Duck(){
};
FlyBehavior flyBehavior;
EatBehavior eatBehavior;
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setEatBehavior(EatBehavior eatBehavior) {
this.eatBehavior = eatBehavior;
}
public void performFly(){
flyBehavior.fly();
}
public void performEat(){
eatBehavior.eat();
}
public void swim(){
System.out.println("所有鸭子都可以游泳");
}
}
测试类
public class TestEat {
public static void main(String[] args) {
Duck duck=new MallardDuck();
duck.setEatBehavior(new EatWithNothing());
duck.performEat();
duck.setEatBehavior(new EatWithGlass());
duck.performEat();
}
}
这样就可以动态的改变新的属性了。
那么最关键的一点来了,我们的子类感觉到了变化吗?
没有,实现的子类的代码没有修改。
也就说这样代码就写活了。
针对借口编程,而不是针对实现编程。
而需要不同的吃的行为只要传进去不同的eat的接口的实现类就好了。
多用组合,少用继承。
好了,这就是策略模式。
定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。