设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
使用设计模式最好的方式是:把模式装进脑子里,然后在你的设计和已有的应用中,寻找何处可以使用它们。以经验复用代替代码复用!
书中例子:
有一套模拟鸭子的游戏。游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫。游戏采用了标准OO技术,设计了一个鸭子超类SuperClass,并让各种鸭子继承此超类。
现在需要为鸭子添加新的行为Fly。如果在SuperClass中添加Fly则会使所有的鸭子对象都具有该方法。但实际中有些鸭子(例如橡皮鸭)是不会飞的。这种情况下只能在橡皮鸭子类中覆盖Fly。这无疑比较丑陋。
到这里其实最直观的想法是:任其继承,我们只需要根据不同的鸭子类型进行覆盖即可,不会飞的鸭子Fly中就什么事都不做,但是这样做会有什么问题呢?
利用继承来提供Duck的行为,这会导致下列哪些缺点?
- 代码在多个子类中重复
- 运行时行为不容易改变
- 很难知道所有鸭子的行为
- 改变会牵一发而动全身,造成其他鸭子不想要的改变
其实最容易想到的可怕结果就是,利用继承的话,后续只要有一个新的Duck子类被创建,就要检查是否需要覆盖Fly方法,而在实际开发中,不断更新是很正常的需求,简直是无穷无尽的噩梦! 同时,原文中鸭子呱呱叫的方法也不尽相同,可以想象出无谓的的工作量。
那么如果利用接口呢?
每个会飞的子类都需要实现Fly接口,会出现大量重复代码,没有做到代码复用。和使用继承的方法差不多,都需要很多额外的工作量!
那到底应该怎么解决呢?现在先让我们看下面两个设计原则:
1.找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起;
2.针对接口编程,而不是针对实现编程。
对于第一条原则,换句话来说,如果每次新的需求一来,都会使某方面的代码发生变化,那么你就可以确定,这部分的代码需要被抽出来,和其他稳定的代码有所区分。
第二条原则的意思是,利用接口代替每个行为,而行为的每个实现都将实现其中的一个接口。这里需要注意,与上述讨论的利用接口解决问题思路是不同的,之前的做法是具体的鸭子子类去实现接口,而现在是专门用一些“行为”类去实现这些接口。因此,鸭子的子类将使用接口所表示的行为,所以实际的“实现”不会被绑死鸭子的子类中。
这样的设计,可以让飞行和呱呱叫的动作被其他对象复用,因为这些行为已经与鸭子类无关了。同时,也可以根据实际新增一些行为,不会影响到既有的行为类,也不会影响“使用”飞行行为的鸭子类。
下面附上代码:
/**
* @author Beat IT
* <p>
* created 2020/7/3 3:19 下午
*/
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck(){
}
public abstract void display();
public void performFly(){
flyBehavior.fly();
}
public void performQuack(){
quackBehavior.quack();
}
public void setFlyBehavior(FlyBehavior newFlyBehavior){
flyBehavior = newFlyBehavior;
}
public void setQuackBehavior(QuackBehavior newQuackBehavior){
quackBehavior = newQuackBehavior;
}
}
/**
* @author Beat IT
* <p>
* created 2020/7/3 3:19 下午
*/
public interface FlyBehavior {
void fly();
}
/**
* @author Beat IT
* <p>
* created 2020/7/3 3:23 下午
*/
public class FlyWithWings implements FlyBehavior{
@Override
public void fly() {
System.out.println("I'm flying!");
}
}
/**
* @author Beat IT
* <p>
* created 2020/7/3 3:24 下午
*/
public class FlyNoWay implements FlyBehavior{
@Override
public void fly() {
System.out.println("I can't fly!");
}
}
/**
* @author Beat IT
* <p>
* created 2020/7/3 3:20 下午
*/
public interface QuackBehavior {
void quack();
}
/**
* @author Beat IT
* <p>
* created 2020/7/3 3:26 下午
*/
public class Quack implements QuackBehavior{
@Override
public void quack() {
System.out.println("Quack!");
}
}
/**
* @author Beat IT
* <p>
* created 2020/7/3 3:26 下午
*/
public class MuteQuqak implements QuackBehavior{
@Override
public void quack() {
System.out.println("Silence");
}
}
/**
* @author Beat IT
* <p>
* created 2020/7/3 3:27 下午
*/
public class Squack implements QuackBehavior{
@Override
public void quack() {
System.out.println("Squack!");
}
}
/**
* @author Beat IT
* <p>
* created 2020/7/3 3:31 下午
*/
public class MallardDuck extends Duck{
@Override
public void display() {
System.out.println("I'm a real MallarDuck!");
}
}
/**
* @author Beat IT
* <p>
* created 2020/7/3 3:33 下午
*/
public class DuckTest {
public static void main(String[] args) {
MallardDuck mallardDuck = new MallardDuck();
mallardDuck.setFlyBehavior(new FlyWithWings());
mallardDuck.setQuackBehavior(new Quack());
mallardDuck.performFly();
mallardDuck.performQuack();
}
}
这就是策略模式,但是个人来说看完书上的讲解还是有点费解,先放上来,后续想通再做更新!