对于设计模式,以前虽然看过一些文章,但是总感觉差那么一点,没有系统的去学习深入一下,以致于在脑海中的思路总不是那么清晰,在项目中对于设计模式的带入感很是不强。所以在下准备静下心来好好整理一下。第一篇便是策略模式。
在百度百科上的介绍:
- 策略模式是指对一系列的算法定义,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
- 策略模式的优点有:策略模式提供了管理相关的算法族的办法、策略模式提供了可以替换继承关系的办法、使用策略模式可以避免使用多重条件转移语句。
组成
- —抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
- —具体策略角色:包装了相关的算法和行为。
- —环境角色:持有一个策略类的引用,最终给客户端调用。
概念
Context(应用场景):
- 需要使用ConcreteStrategy提供的算法。
- 内部维护一个Strategy的实例。
- 负责动态设置运行时Strategy具体的实现算法。
- 负责跟Strategy之间的交互和数据传递。
Strategy(抽象策略类):
- 定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,Context使用这个接口调用不同的算法,一般使用接口或抽象类实现。
- ConcreteStrategy(具体策略类):
- 实现了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的进化了行动方式:
飞行
以上,策略模式简单使用。
- 优点:在一些情况下可以复用很多代码,增强代码的扩展行。
- 缺点:有可造成会有很多策略类的情况,并且策略类的实现,要求基类必须定义好所以接口对象,基类子类不管是否需要,都必须知道所以策略。
仅此记录策略模式的学习笔记。与大家共享,请大家多多建议。