1.场景问题解决
1.1 场景描述
模拟鸭子游戏,鸭子能叫,能游泳,鸭子还有各种品种,绿头鸭,红头鸭.
1.2 OO设计
类图如下:
鸭子抽象类 Duck---->叫声和游泳是普通方法,display是抽象方法,继承的类要实现该方法
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~~");
}
}
GreenHeadDuck 绿头鸭
public class GreenHeadDuck extends Duck {
@Override
public void display() {
System.out.println("**GreenHead**");
}
}
RedHeadDuck 红头鸭
public class RedHeadDuck extends Duck {
@Override
public void display() {
System.out.println("**RedHead**");
}
}
main
public class StimulateDuck {
public static void main(String[] args) {
GreenHeadDuck mGreenHeadDuck = new GreenHeadDuck();
RedHeadDuck mRedHeadDuck = new RedHeadDuck();
mGreenHeadDuck.display();
mGreenHeadDuck.Quack();
mGreenHeadDuck.swim();
mRedHeadDuck.display();
mRedHeadDuck.Quack();
mRedHeadDuck.swim();
}
}
1.3 需求变动,需要增加飞(fly())的功能
鸭子抽象类 Duck---->叫声和游泳是普通方法,display是抽象方法,继承的类要实现该方法
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 绿头鸭–继承默认就有了Fly功能
public class RedHeadDuck extends Duck {
@Override
public void display() {
System.out.println("**RedHead**");
}
}
RedHeadDuck 红头鸭 --没有fly功能还要继承覆盖
public class RedHeadDuck extends Duck {
@Override
public void display() {
System.out.println("**RedHead**");
}
public void Fly() {
System.out.println("~~I cannot fly~~");
}
}
main
public class StimulateDuck {
public static void main(String[] args) {
GreenHeadDuck mGreenHeadDuck = new GreenHeadDuck();
RedHeadDuck mRedHeadDuck = new RedHeadDuck();
mGreenHeadDuck.display();
mGreenHeadDuck.Fly();
mGreenHeadDuck.Quack();
mGreenHeadDuck.swim();
mRedHeadDuck.display();
mRedHeadDuck.Quack();
mRedHeadDuck.swim();
mRedHeadDuck.Fly();
}
}
1.4 带来问题
带来问题: 在的抽象父类中增加了fly()的方法,那么所有的子类都有了fly()的方法,如果RedHeadDuck鸭子不能飞翔,则还要覆盖fly()方法不让fly();
**继承的问题:**对类的局部改动,尤其超类的局部改动,会影响其他部分。影响会有溢出效应
当方法越来越多的时候,个性化越来越多的时候,那么各个子类需要覆盖的方法越来越多。
2.用设计模式改进
2.1 分析
2.1.1 需要新的设计方式,应对项目的扩展性,降低复杂度:
1)分析项目变化与不变部分,提取变化部分,抽象成接口+实现; 2)鸭子哪些功能是会根据新需求变化的?叫声、飞行…
2.1.1 新增行为接口
接口:
public interface FlyBehavior{
void fly();
}
public interface QuackBehavior{
void quack();
};
好处:新增行为简单,行为类更好的复用,组合更方便。既有继承带来的复用好处,没 有挖坑
2.2 重新设计类图
2.3 重新设计代码
Duck
public abstract class Duck {
FlyBehavior mFlyBehavior;
QuackBehavior mQuackBehavior;
public Duck() {
}
public void Fly() {
mFlyBehavior.fly();
}
public void Quack() {
mQuackBehavior.quack();
}
public abstract void display();
public void SetQuackBehavoir(QuackBehavior qb) {
mQuackBehavior = qb;
}
public void SetFlyBehavoir(FlyBehavior fb) {
mFlyBehavior = fb;
}
public void swim() {
System.out.println("~~im swim~~");
}
}
FlyBehavior接口及实现
//FlyBehavior接口
public interface FlyBehavior {
void fly();
}
public class BadFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("--BadFly--");
}
}
public class GoodFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("--GoodFly--");
}
}
public class NoFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("--NoFly--");
}
}
QuackBehavior接口及实现
public interface QuackBehavior {
void quack();
};
public class GaGaQuackBehavior implements QuackBehavior{
@Override
public void quack() {
System.out.println("__GaGa__");
}
}
public class GeGeQuackBehavior implements QuackBehavior {
@Override
public void quack() {
System.out.println("__GeGe__");
}
}
public class NoQuackBehavior implements QuackBehavior {
@Override
public void quack() {
System.out.println("__NoQuack__");
}
}
Duck及Duck实现
public abstract class Duck {
FlyBehavior mFlyBehavior;
QuackBehavior mQuackBehavior;
public Duck() {
}
public void Fly() {
mFlyBehavior.fly();
}
public void Quack() {
mQuackBehavior.quack();
}
public abstract void display();
public void SetQuackBehavoir(QuackBehavior qb) {
mQuackBehavior = qb;
}
public void SetFlyBehavoir(FlyBehavior fb) {
mFlyBehavior = fb;
}
public void swim() {
System.out.println("~~im swim~~");
}
}
public class GreenHeadDuck extends Duck {
public GreenHeadDuck() {
mFlyBehavior = new GoodFlyBehavior();
mQuackBehavior = new GaGaQuackBehavior();
}
@Override
public void display() {
System.out.println("**GreenHead**");
}
}
public class RedHeadDuck extends Duck {
public RedHeadDuck() {
mFlyBehavior = new BadFlyBehavior();
mQuackBehavior = new GeGeQuackBehavior();
}
@Override
public void display() {
System.out.println("**RedHead**");
}
}
Main
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();
mRedHeadDuck.SetFlyBehavoir(new NoFlyBehavior());
mRedHeadDuck.Fly();
mRedHeadDuck.SetQuackBehavoir(new NoQuackBehavior());
mRedHeadDuck.Quack();
}
}
3.设计模式总结
3.1 定义
策略模式: 分别封装行为接口,实现算法族,超类里放行为接口对象,在子类里具体设 定行为对象。原则就是:分离变化部分,封装接口,基于接口编程各种功能。此模式让行为 算法的变化独立于算法的使用者。
策略模式: 定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户
3.2 分析思路
1、分析项目中变化部分与不变部分,把他们独立出来,不要和那些不需要变化的代码混在一起2、多用组合少用继承;用行为类组合,而不是行为的继承。更有弹性3、设计模式有没有相应的库直接使用?有些库或框架本身就用某种设计模式设计的4、如果找不到适用的模式怎么办
3.3 总结设计原则
设计原则1:分析项目中变化部分与不变部分,把他们独立出来,不要和那些不需要变化的代码混在一起设计原则2:针对接口编程,而不是针对实现编程设计原则3:多用组合,少用封装
4. 设计模式使用场景及注意
5.参考文章
读headFirst设计模式 - 策略模式
13种UML简介、工具及示例
内容总计于HeadFirst设计模式及相关视频