设计模式之策略模式

对于设计模式,以前虽然看过一些文章,但是总感觉差那么一点,没有系统的去学习深入一下,以致于在脑海中的思路总不是那么清晰,在项目中对于设计模式的带入感很是不强。所以在下准备静下心来好好整理一下。第一篇便是策略模式。

在百度百科上的介绍:

  • 策略模式是指对一系列的算法定义,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
  • 策略模式的优点有:策略模式提供了管理相关的算法族的办法、策略模式提供了可以替换继承关系的办法、使用策略模式可以避免使用多重条件转移语句。

组成

  • —抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
  • —具体策略角色:包装了相关的算法和行为。
  • —环境角色:持有一个策略类的引用,最终给客户端调用。

概念
Context(应用场景):

  1. 需要使用ConcreteStrategy提供的算法。
  2. 内部维护一个Strategy的实例。
  3. 负责动态设置运行时Strategy具体的实现算法。
  4. 负责跟Strategy之间的交互和数据传递。

Strategy(抽象策略类):

  1. 定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,Context使用这个接口调用不同的算法,一般使用接口或抽象类实现。
  2. ConcreteStrategy(具体策略类):
  3. 实现了Strategy定义的接口,提供具体的算法实现。

以上可能有些不好理解,说得通俗易懂一点,其实策略模式顾名思义,其重点应放在“策略”两个字上,建立一系列备用的“策略”,按功能需要决定使用何种“策略”。如何理解“策略”、建立“策略”,将“策略”运用到代码中呢?在小生的理解来看,主要逻辑在于通用功能与动态改变功能的区分、提取以及抽取。

比如说,老板说我们要生产动物,但是每类动物都要标明其行动方式(行走,飞行,游泳)与进食方式(素食,肉食)。如果目前需求是狗狗,黄雀两种动物,你只用写两个类,每个类里面互不相干,各自实现狗狗与黄雀的共同特征以及不一样的行动方式与进食方式,完美收工。但是…等等,老板说,唉,我们又要增加10类动物,以后还会持续不断新增,这样岂不是每一类都要重复写一次,但是,行走,飞行,素数,肉食等功能对于动物来说都是共通的,只是有或者无的区别,这就是我们所说的“策略”了。将行动和进食抽象出来,各自实现,再按具体需要合理使用,这就是策略模式了。

简单的说,抽象出功能或者算法族的接口,需要一个基类定义好各个接口的对象,接口的具体实现需要子类去确定。

进食接口EatBehavior:

public interface EatBehavior {
    void eat();
}

行为接口MoveBehavior:

public interface MoveBehavior {
    void move();
}

功能接口实现类,这就是所谓的准备好一系列的策略:

public class MeatEat implements EatBehavior{
    public void eat() {
        System.out.println("肉食");
    }
}
public class VegetarianEat implements EatBehavior{

    public void eat() {
        System.out.println("素食");
    }
}
public class FlyMove implements MoveBehavior {
    public void move() {
        System.out.println("飞行");
    }
}
public class WalkMove implements MoveBehavior{
    public void move() {
        System.out.println("步行");
    }
}

最重要的基类Animals,这里就体现了面向对象设计的六大原则之一的里氏代换原则,两个对象的定义为接口的对象,以便于子类可以实现不同的策略组合,两个set方法可以实现子类运行时动态改变其行为方式:

public class Animals {
    //抽象出去的两个会变化行为:进食,行动
    protected EatBehavior eatBehavior;
    protected MoveBehavior moveBehavior;

    public void eat(){
        eatBehavior.eat();
    }

    public void move(){
        moveBehavior.move();
    }

    /**
     * 公共行为属性
     */
    public void smile(){
        System.out.println("微笑,say:hello word");
    }

    public void setEatBehavior(EatBehavior eatBehavior) {
        this.eatBehavior = eatBehavior;
    }

    public void setMoveBehavior(MoveBehavior moveBehavior) {
        this.moveBehavior = moveBehavior;
    }
}

子类黄雀Bird的实现:

主要是
eatBehavior = new VegetarianEat();
moveBehavior = new FlyMove();的策略选择实现确定了黄雀的行为与进食方式

public class Bird extends Animals{
    Bird(){
        eatBehavior = new VegetarianEat();
        moveBehavior = new FlyMove();
    }

    //...
}

子类狗狗Dog的实现:

主要是 eatBehavior = new MeatEat();
moveBehavior = new WalkMove();的实现确定了狗狗的行为与进食方式

public class Dog extends Animals{
    Dog(){
        eatBehavior = new MeatEat();
        moveBehavior = new WalkMove();
    }

    //...
}

万事具备,就差检验结果

public class test {
    public static void main(String[] args) {
        Animals dog = new Dog();
        Animals bird = new Bird();

        //dog与bird共同固定属性
        dog.smile();
        bird.smile();

        System.out.println("dog的进食方式:");
        dog.eat();
        System.out.println("bird的进食方式:");
        bird.eat();

        System.out.println("dog的行动方式:");
        dog.move();
        System.out.println("bird的行动方式:");
        bird.move();

        //运行时动态改变其行为方式
        System.out.println("bird的改变了方式:");
        bird.setEatBehavior(new VegetarianEat());
        bird.eat();
        System.out.println("dog的进化了行动方式:");
        dog.setMoveBehavior(new FlyMove());
        dog.move();

    }
}

打印结果:

微笑,say:hello word
微笑,say:hello word
dog的进食方式:
肉食
bird的进食方式:
素食
dog的行动方式:
步行
bird的行动方式:
飞行
bird的改变了方式:
素食
dog的进化了行动方式:
飞行

以上,策略模式简单使用。

  • 优点:在一些情况下可以复用很多代码,增强代码的扩展行。
  • 缺点:有可造成会有很多策略类的情况,并且策略类的实现,要求基类必须定义好所以接口对象,基类子类不管是否需要,都必须知道所以策略。

仅此记录策略模式的学习笔记。与大家共享,请大家多多建议。

代码传送门:git@github.com:pffo/pattern.git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值