一.设计模式入门
设计模式是人们在面对同类型软件工程设计问题所总结出的一些有用经验。模式不是代码,而是某类问题的通用设计解决方案。
4人组Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides总结写了《设计模式》。
设计模式的优点和用途。
学习设计模式最好的方式:在你的设计和以往的工程里寻找何处可以使用它们。
设计模式的本质目的是使软件工程在维护性、扩展性、变化性、复杂度方面成O(N)。
OO是基础原则,设计模式是具体方法、工具。
在java里IO流的类设计,为什么把BufferedReader设计成:
new BufferedReader(new FileReader("F:\test.java"));
而不是设计成:BufferedReader extends FileReader;然后new BufferedReader("F:\test.java");
按继承扩展的方式,它将变成N*N的方式,有N个超类要映射到N个子类,复杂程度是N*N,用装饰者模式将变成N的关系,复杂度将降一个级别。
二.策略模式原理
1.模拟鸭子项目
从项目“模拟鸭子游戏”开始。父类实现基本方法和功能,不清楚的方法交给子类去实现。
2.项目的新需求
给鸭子增加飞的功能。OO设计方法的代码:
Duck.java
package com.bijian.study.oo;
/**
* 鸭的抽象类
* @author bijian
*
*/
public abstract class Duck {
public Duck() {
}
public void quack() {
System.out.println("~~gaga~~");
}
public abstract void display();
public void swim() {
System.out.println("~~im swim~~");
}
public void fly() {
System.out.println("~~im fly~~");
}
}
GreenHeadDuck.java
package com.bijian.study.oo;
/**
* 绿头鸭
* @author bijian
*
*/
public class GreenHeadDuck extends Duck {
@Override
public void display() {
System.out.println("**GreenHead**");
}
@Override
public void fly() {
System.out.println("~~no fly~~~");
}
}
RedHeadDuck.java
package com.bijian.study.oo;
/**
* 红头鸭
* @author bijian
*
*/
public class RedHeadDuck extends Duck {
@Override
public void display() {
System.out.println("**RedHead**");
}
}
StimulateDuck.java
package com.bijian.study.oo;
/**
* 主方法
* @author bijian
*/
public class StimulateDuck {
public static void main(String[] args) {
GreenHeadDuck mGreenHeadDuck = new GreenHeadDuck();
RedHeadDuck mRedHeadDuck = new RedHeadDuck();
mGreenHeadDuck.display();
mGreenHeadDuck.quack();
mGreenHeadDuck.swim();
mGreenHeadDuck.fly();
mRedHeadDuck.display();
mRedHeadDuck.quack();
mRedHeadDuck.swim();
mRedHeadDuck.fly();
}
}
运行结果:
**GreenHead** ~~gaga~~ ~~im swim~~ ~~no fly~~~ **RedHead** ~~gaga~~ ~~im swim~~ ~~im fly~~
3.用OO原则解决新需求的不足
这个fly让所有子类都会飞了,这是不科学的。
继承的问题:对类的局部改动,尤其超类的局部改动,会影响其他部分,影响会有溢出效果。超类挖的一个坑,每个子类都要来填,增加工作量,复杂度O(N^2),不是好的设计方式。
a.继续尝试用OO原理来解决,那就是在子类中覆盖父类的方法。
但如果子类非常多,需要在太多的子类中去覆盖父类的方法。
b.只在子类中实现对应的方法,需要的实现飞,不需要的不实现。但这样代码没有复用了,重复代码出现,代码复用性降低。
且如果又有新的需求,如石头鸭子,它既不会飞,也不会叫,也不会游泳。所有的方法都要覆盖掉。
4.用策略模式来解决新需求
需要新的设计方式,应对项目的扩展性,降低复杂度。
a.分析项目变化与不变部分,提取变化部分,抽象成接口+实现
b.鸭子哪些功能是会根据新需求变化的?叫声、飞行...,抽象成接口,形成行为族
c.好处:新增行为简单,行为类更好的复用,组合更方便。既有继承带来的复用好处,没有挖坑。
5.重新设计模拟鸭子项目
/**
* 抽象类里面加了两个行为对象
* 具体飞、叫不具体实现,直接调用行为的实现
* @author bijian
*
*/
public abstract class Duck {
FlyBehavior mFlyBehavior;
QuackBehavior mQuackBehavior;
public Duck() {
}
public void fly() {
mFlyBehavior.fly();
}
public void Quack() {
mQuackBehavior.quack();
}
public abstract void display();
}
6.总结策略模式定义
绿头鸭、石头鸭在构造方法用new一个行为族对象来展现它的行为,而不是具体把行为代码写在类的对象里。
策略模式:分别封装行为接口,实现算法族,超类里放行为接口对象,在子类里具体设定行为对象。原则就是:分离变化部分,封装接口,基于接口编程各种功能。此模式让行为算法的变化独立于算法的使用者。
三.策略模式示例演示
FlyBehavior.java
package com.bijian.study.strategy.flybehavior;
/**
* 飞行行为
* @author bijian
*
*/
public interface FlyBehavior {
void fly();
}
BadFlyBehavior.java
package com.bijian.study.strategy.flybehavior.impl;
import com.bijian.study.strategy.flybehavior.FlyBehavior;
public class BadFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("--BadFly--");
}
}
GoodFlyBehavior.java
package com.bijian.study.strategy.flybehavior.impl;
import com.bijian.study.strategy.flybehavior.FlyBehavior;
public class GoodFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("--GoodFly--");
}
}
NoFlyBehavior.java
package com.bijian.study.strategy.flybehavior.impl;
import com.bijian.study.strategy.flybehavior.FlyBehavior;
public class NoFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("--NoFly--");
}
}
QuackBehavior.java
package com.bijian.study.strategy.quackbehavior;
/**
* 叫的行为
* @author bijian
*
*/
public interface QuackBehavior {
void quack();
}
GaGaQuackBehavior.java
package com.bijian.study.strategy.quackbehavior.impl;
import com.bijian.study.strategy.quackbehavior.QuackBehavior;
public class GaGaQuackBehavior implements QuackBehavior {
@Override
public void quack() {
System.out.println("~~gaga~~");
}
}
GeGeQuackBehavior.java
package com.bijian.study.strategy.quackbehavior.impl;
import com.bijian.study.strategy.quackbehavior.QuackBehavior;
public class GeGeQuackBehavior implements QuackBehavior {
@Override
public void quack() {
System.out.println("~~gege~~");
}
}
NoQuackBehavior.java
package com.bijian.study.strategy.quackbehavior.impl;
import com.bijian.study.strategy.quackbehavior.QuackBehavior;
public class NoQuackBehavior implements QuackBehavior {
@Override
public void quack() {
System.out.println("~~NoQuack~~");
}
}
Duck.java
package com.bijian.study.strategy.duck;
import com.bijian.study.strategy.flybehavior.FlyBehavior;
import com.bijian.study.strategy.quackbehavior.QuackBehavior;
/**
* 抽象类里面加了两个行为对象
* 具体飞、叫不具体实现,直接调用行为的实现
* @author bijian
*
*/
public abstract class Duck {
FlyBehavior mFlyBehavior;
QuackBehavior mQuackBehavior;
public void setmFlyBehavior(FlyBehavior mFlyBehavior) {
this.mFlyBehavior = mFlyBehavior;
}
public void setmQuackBehavior(QuackBehavior mQuackBehavior) {
this.mQuackBehavior = mQuackBehavior;
}
public Duck() {
}
public void fly() {
mFlyBehavior.fly();
}
public void quack() {
mQuackBehavior.quack();
}
public abstract void display();
public void swim() {
System.out.println("--im swim--");
}
}
GreenHeadDuck.java
package com.bijian.study.strategy.duck;
import com.bijian.study.strategy.flybehavior.impl.GoodFlyBehavior;
import com.bijian.study.strategy.quackbehavior.impl.GaGaQuackBehavior;
public class GreenHeadDuck extends Duck {
public GreenHeadDuck() {
mFlyBehavior = new GoodFlyBehavior();
mQuackBehavior = new GaGaQuackBehavior();
}
@Override
public void display() {
System.out.println("**GreenHead**");
}
}
RedHeadDuck.java
package com.bijian.study.strategy.duck;
import com.bijian.study.strategy.flybehavior.impl.BadFlyBehavior;
import com.bijian.study.strategy.quackbehavior.impl.GeGeQuackBehavior;
public class RedHeadDuck extends Duck {
public RedHeadDuck() {
mFlyBehavior = new BadFlyBehavior();
mQuackBehavior = new GeGeQuackBehavior();
}
@Override
public void display() {
System.out.println("**RedHead**");
}
}
StimulateDuck.java
package com.bijian.study.strategy;
import com.bijian.study.strategy.duck.Duck;
import com.bijian.study.strategy.duck.GreenHeadDuck;
import com.bijian.study.strategy.duck.RedHeadDuck;
import com.bijian.study.strategy.flybehavior.impl.NoFlyBehavior;
import com.bijian.study.strategy.quackbehavior.impl.NoQuackBehavior;
public class StimulateDuck {
public static void main(String[] args) {
Duck mGreenHeadDuck = new GreenHeadDuck();
Duck mRedHeadDuck = new RedHeadDuck();
mGreenHeadDuck.display();
mGreenHeadDuck.fly();
mGreenHeadDuck.quack();
mGreenHeadDuck.swim();
mRedHeadDuck.display();
mRedHeadDuck.fly();
mRedHeadDuck.quack();
mRedHeadDuck.swim();
mRedHeadDuck.display();
//在使用过程中动态的改变它的行为
System.out.println("-------------------------");
mRedHeadDuck.setmFlyBehavior(new NoFlyBehavior());
mRedHeadDuck.fly();
System.out.println("-------------------------");
mRedHeadDuck.setmQuackBehavior(new NoQuackBehavior());
mRedHeadDuck.quack();
}
}
运行结果:
**GreenHead** --GoodFly-- ~~gaga~~ --im swim-- **RedHead** --BadFly-- ~~gege~~ --im swim-- **RedHead** ------------------------- --NoFly-- ------------------------- ~~NoQuack~~
四.策略模式的注意点
1.分析项目中变化部分与不变部分
在鸭子项目里,飞行和叫声是变化的,所以将其抽取出来,将其抽象成接口和具体实现对象(接口和对象行为族)。
2.多用组合少用继承;用行为类组合,而不是行为的继承。更有弹性
行为族对象的组合,行为族之间是独立的。
3.设计模式有没有相应的库直接使用?有些库或框架本身就用某种设计模式设计的
没有,它是经验的总结,是一个方法。用这种模式方法设计类、行为、接口。当然,很多库、框架就是用设计模式设计出来的。
4.如果找不到适用的模式怎么办
进一步分析项目,基本上都能用某种模式或多种模式的组合解决。当然,如果真遇到这种项目,那就是用OO基本原则,抽象、分析设计超类、继承、子类方法来做。