zoukankan      html  css  js  c++  java
  • 初学设计模式:策略模式

    tags:blog 设计模式 2015-03

    初学设计模式: 策略模式

    引入: 策略模式用来做什么? 为什么要用策略模式?

    需求:

    现在我是一名开发者, 我需要开发一个关于鸭子的模拟系统.这个系统可能会有 MallardDuck, RedHeadDuck 鸭子是能够飞的,他们需要有 Fly 方法, 而且都是能发出叫声和游泳的,即有 swim 和 quack 方法.
    最简单的代码设计方式:用Duck 作为超类,用MarllardDuck & RedHeadDuck 分别继承Duck类:

    public abstract class Duck{
        public void Fly(){
    		System.out.println("FLy...");
    	}
    
    	public void Quack(){
    		System.out.println("Quack");
    	}
    	
    	public void swim(){
    		System.out.println("swim");
    	}
    	
    	public void display(){
    	    System.out.println("duck");
    	}
    }
    
    //继承上面的DUCK,从而有了 Fly & display 方法
    public class MallardDuck extends Duck{
    	public void display(){
    		System.out.println("marllardDuck");
    	}
    }
    
    public class RedHeadDuck extends Duck{
    	public void display(){
    		System.out.println("RedHeadDuck");
    	}
    }
    
    

    上面的设计目前是很合理的,但是需求总是不固定的. 比方说我们现在增加了两种鸭子:RubberDuck(橡皮鸭) & DecoyDuck(诱饵鸭). 前者不会飞,后者既不会飞也不会叫.这个时候用上面的设计就显得不合理了, 当继承 Duck的时候会将 quack & fly 方法同时继承过来, 你当然可以通过复写 fly & quack 方法来使得继承过来的方法无效, 但是这里继承还是暴露出来了它的问题:

    • 代码在多个子类中重复
    • 运行时不能改变
    • 牵一发而动全身
    • 很难知道鸭子的所有行为

    既然从Duck继承 fly & quack 会有这么多的问题,那么将 fly & quack 写成接口,然后用 Duck 的子类去实现这个接口如何? 答案当然是不好,接口是无法实现复用目的的! 这样会造成大量的冗余代码,每个具有上述方法的 Duck 的子类都会去重写 fly & quack 方法, 而且最最可怕的是, 一旦fly 方法需要一点变更, 必须要修改每一个 Duck 子类!

    既然传统的方法无法解决问题,那就需要一些改变.

    OO的设计原则说:

    应当找出应用中可能需要变化之处, 把他独立出来.

    应当把会变化的部分取出并封装起来, 以后便可以容易的扩充或改动此部分, 而不影响其他的功能.

    上述概念很简单, 但却是每个设计模式的精神所在: 让系统中某个部分的改变不会影响到其他的部分.

    所以, 既然 fly & quack 是变化的地方, 我们就应该把它 取出&封装 :

    //Duck超类
    public abstract class Duck {
    	protected FlyBehavior flyBehavior;
    	protected QuackBehavior quackBehavior;
    	
    	public void performFly(){
    		flyBehavior.fly();
    	}
    
    	public void performQuack(){
    		quackBehavior.quack();
    	}
    	
    	...
    }
    
    //fly接口
    public interface FlyBehavior {
    	void fly();
    }
    
    public class FlyWithWings implements FlyBehavior {
    	public void fly() {
    		System.out.println("I'm flying!");
    	}
    }
    
    //quack接口
    public interface QuackBehavior {
    	void quack();
    }
    
    public class Quack implements QuackBehavior{
    	public void quack(){
    		System.out.println("quack");
    	}
    }
    
    //Duck 的继承类
    public class ADuck extends Duck {
    	public ADuck() {
    		flyBehavior = new FlyWithWings();
    		quackBehavior = new Quack();
    	}
    }
    
    

    按照以上方法定义出来的Duck 类既实现了代码的最大复用,同时又避免了陷入扩展的困境.
    若果需要,我们还可以在给ADuck 的实例不同的fly 或是 quack 方法,以达到在 运行时改变的目的.

    本例中, fly & quack 实际上是一个个具体的方法, 通过面向接口编程的思想, 我们只看重fly & quack 的接口,而将实现委托给 fly & quack 的具体实现类来执行.这也就是策略模式.

    以下是策略模式的正式解释:

    定义了算法簇,分别封装起来,让他们之间可以互相替换.此模式让算法的变化独立于使用算法的客户.

    通过这个例子,我才算是真正明白了策略模式,good,加油!

  • 相关阅读:
    Super
    多态
    方法覆盖 和toString方法的作用
    Static 静态+this
    构造方法 + 继承
    使用方法重载的优缺点
    Erlang 简介与样例分析
    Assassin's Creed 4: Black Flag --《刺客信条4; 黑旗》
    DEVIL MAY CRY V:《鬼泣5》
    Valiant Hearts: The Great War -- 《勇敢的心》
  • 原文地址:https://www.cnblogs.com/bugmaster/p/4353519.html
Copyright © 2011-2022 走看看