写在前面:上个学期刚学了SSH,参加了几个竞赛写了几个小项目,但是也只是简单的套用SSH的套路,也不是很清楚为什么要用略显臃肿的框架,只听学长提起什么松耦合易维护,不是很理解为什么框架就可以做到这些。后来学长推荐了《Head First 设计模式》,暑假的时候粗略看了几章,看的时候就总有豁然开朗的感觉,噢~原来框架是通过这些设计模式来达到“松耦合”、“易维护”。开学之后白天上课,下课了跟着老师做项目,晚上回到寝室变得没有以前那么勤奋。想起暑假看到一半的设计模式,暑假看的现在想起来已经有些模糊,决定重新看起,把每一章的收获记在这里,为了以后查看方便,另外写博客也算对自己的一个督促吧^ ^
======================================================================================================================================
策略模式:
定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的用户。
涉及设计原则:
1.找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起
2.针对接口编程,而不是针对实现编程
3.多用组合,少用继承(“有一个”可能比“是一个”更好)
问题简单描述:
在鸭子模拟游戏里有个鸭子超类,出现的各种鸭子都继承这个鸭子超类,可以直接调用父类的非抽象方法如:fly()、quack(),需要实现有特性的父类抽象方法如:display。后来出现了不会飞的橡皮鸭子或者不会叫的木头鸭子,因为直接继承了鸭子超类就出现了不会飞的橡皮鸭子fly,不会叫的木头鸭子quack这样的荒唐事。
解决思路:
把fly、quack等需要变化的地方独立出来,写成接口,在鸭子超类中组合,而不是作为鸭子超类的一个方法(非抽象方法会导致上述的荒唐,抽象方法又会导致代码的大量重复)。
UML图:
实现代码:
Duck超类
package strategy;
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck() {
}
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
/*
* 添加set方法实现动态修改
*/
public FlyBehavior getFlyBehavior() {
return flyBehavior;
}
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public QuackBehavior getQuackBehavior() {
return quackBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
FlyBehavior接口
package strategy;
/**
* 鸭子飞行接口
* @author terry
*
*/
public interface FlyBehavior {
public void fly();
}
QuackBehavior接口
package strategy;
/**
* 鸭子叫接口
* @author terry
*
*/
public interface QuackBehavior {
public void quack();
}
FlyBehavior实现类
package strategy;
/**
* 不会飞鸭子组合的实现类
* @author terry
*
*/
public class FlyNoWay implements FlyBehavior{
@Override
public void fly() {
System.out.println("i can't fly!");
}
}
package strategy;
/**
* 会飞鸭子组合的实现类
* @author terry
*
*/
public class FlyWihWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("I'm flying~");
}
}
QuackBehavior实现类
package strategy;
/**
* 呱呱叫鸭子组合的实现类
* @author terry
*
*/
public class Quack implements QuackBehavior{
@Override
public void quack() {
System.out.println("Quack!");
}
}
package strategy;
/**
* 不能叫的鸭子组合的实现类
* @author terry
*
*/
public class QuackNoWay implements QuackBehavior{
@Override
public void quack() {
System.out.println("i can't quack");
}
}
正常鸭子子类
package strategy;
/**
* 正常鸭子类
* @author terry
*
*/
public class NormalDuck extends Duck {
public NormalDuck(){
//初始化时可以飞可以叫
flyBehavior=new FlyWihWings();
quackBehavior=new Quack();
}
}
木头鸭子子类
package strategy;
/**
* 木头鸭子
* @author terry
*
*/
public class WoodDuck extends Duck {
public WoodDuck() {
//初始化时不可以飞不可以叫
flyBehavior = new FlyNoWay();
quackBehavior = new QuackNoWay();
}
}
测试类
package strategy;
public class Test {
public static void main(String[] args){
//正常鸭子
Duck normalDuck=new NormalDuck();
normalDuck.performFly();
normalDuck.performQuack();
//木头鸭子
Duck woodDuck=new WoodDuck();
woodDuck.performFly();
woodDuck.performQuack();
//正常鸭子翅膀受伤
normalDuck.setFlyBehavior(new FlyNoWay());
normalDuck.performFly();
//正常鸭子嗓子受伤
normalDuck.setQuackBehavior(new QuackNoWay());
normalDuck.performQuack();
}
}
输出结果
个人感觉策略模式清奇的地方就是以往一直觉得类是代表某种“东西”,具备了状态与行为,在策略模式中用一个类来代表了一个行为(FlyBehavior、QuackBehavior两个接口的实现类)。书中tip了一下针对接口编程是指“针对超类型编程”,以前听说过面向接口编程,一直以为指的接口就是interface,看书的时候想interface不就是类中方法都是抽象方法么,超类编程也正是因为abstract和多态显得神奇。有了策略模式,在架构时将未来可能需要变化的部分抽离出来封装就会为以后需求变化的时候代码更改省下了很大精力。
欢迎批评指正^ ^