设计模式-策略模式的完整代码示例及测试验证

news2024/9/20 18:44:32

策略模式

什么是策略模式?

策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互换。
策略模式使得算法可以在不影响客户端的情况下发生变化。策略模式主要解决的是在有多种算法相似的情况下,使用if…else或者switch…case来选择具体算法的问题。

策略模式构成

  1. 策略接口:定义了所有支持的算法的公共接口。
  2. 具体策略类:实现了策略接口,封装了具体的算法。
  3. 上下文类:使用一个具体策略来完成所要的行为。

优缺点

  • 优点
  1. 易于扩展:增加新算法时,只需要新增具体策略类,不需要修改已有的代码,符合开闭原则。
  2. 消除冗长的条件判断语句:通过策略类的替换,避免了大量的if…else或switch…case语句。
  • 缺点
  1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
  2. 增加了系统中类的数量,每个具体策略都会产生一个新的类。

与工厂模式的区别

  1. 关注点不同

    1. 策略模式

      关注的是行为的替换和变化。通过策略模式,可以在运行时改变行为,而不需要修改客户端代码。 强调的是行为的选择和变化,而不是对象的创建。

    2. 工厂模式

      关注的是对象的创建和实例化。通过工厂模式,可以将对象的创建过程封装起来,从而让客户端代码不依赖具体的类。强调的是创建产品对象的过程

  2. 结构不同

    1. 策略模式

      包含一个上下文类(Context),多个策略接口(Strategy),以及策略接口的具体实现类(ConcreteStrategy)。
      客户端通常会持有一个上下文对象,并在上下文对象中设置或传递具体的策略对象。

    2. 工厂模式:
      包含一个工厂接口(或抽象类),具体工厂类(ConcreteFactory),以及创建的产品类(Product)。
      工厂模式有几种变体,如简单工厂、工厂方法和抽象工厂。不同的变体有不同的结构和用法。


策略模式正篇

之所以这个章节才称为正篇,是因为上面的一堆总结并不能真正让人理解策略模式,除非你已经很懂策略模式了。
接下来我希望用更简单的方式,用说人话的方式来讲清楚什么是策略模式。
故事要从朋友的一句话说起,策略模式不就是高级的if-else嘛。


知识点回顾

要弄清楚策略模式的本质,其实还是要回到最开始学习java面向对象的时候,万物皆对象,面向对象的三大特征: 封装、继承、多态。


场景案例

继续请出工厂模式中的牛马们来举例。
现在有 猫、狗、2种动物,都被圈养在动物园中,他们各自的介绍方式都不一样,但是都用腿走两步,在动物园我们可以召唤猫、狗、来观看他们自我介绍和走的行为


  • 案例UML类图
    在这里插入图片描述

Abstract抽象类

1,动物父类(Animal)

由于猫、狗、是动物,有相同地走的行为,所以可以抽象出一个Abstract Animal动物类,然后让猫、狗继承这个动物类。
因为走的行为是相同的,所以在父类中直接进行了方法的具体实现,而自我介绍的方式各不一样,所以定义了一个抽象的方法,由子类去具体实现。


/**
 * @Author: javafa
 * @Date: 2024/7/31 16:06
 * @Description: 动物类:别总牛马牛马的称呼,人家学名叫动物
 */
public abstract class Animal {

   /**
    * @Author: javafa
    * @Description: 每种动物 都要进自我介绍,由子类去具体实现
    * @Date: 2024/7/31 16:10
    * @Param:
    * @return: void
    **/
   public abstract void speak();

   /**
    * @Author: javafa
    * @Description: 所有动物都有相同的行为特征:走两步
    * @Date: 2024/7/31 16:09
    * @Param:
    * @return: void
    **/
   public void walk() {
      System.out.println("没事儿走两步");
   }

}

2,具体动物实现类

  1. 猫—喵喵喵
/**
 * @Author: javafa
 * @Date: 2024/7/31 16:24
 * @Description: 动物-猫
 */
public class Cat extends Animal{
    @Override
    public void speak() {
        System.out.println("喵新人说:喵喵喵!");
    }
}

  1. 狗—旺旺旺

/**
 * @Author: javafa
 * @Date: 2024/7/31 16:24
 * @Description: 动物-大黄狗
 */
public class Dog extends Animal{
    /**
     * @Author: javafa
     * @Description: 旺财说
     * @Date: 2024/7/31 16:38
     * @Param:
     * @return: void
    **/
    @Override
    public void speak() {
        System.out.println("旺财说:汪汪汪!");
    }
}

3,动物园

动物园里可以通过动物类型来召唤任何一种动物,去观察自我介绍和走两步的行为。


/**
 * @Author: javafa
 * @Date: 2024/7/31 16:04
 * @Description: 牛马们所在的动物园
 */
public class Zoo {

   Animal animal;//动物父类

   /**
    * @Author: javafa
    * @Description: 通过动物类型,来召唤(实例化)不同的动物
    * @Date: 2024/7/31 17:19
    * @Param: animalType
    * @return:
    **/
   public Zoo(String animalType) {
      if (animalType.equals("dog")) {
         animal = new Dog();
      } else if (animalType.equals("cat")) {
         animal = new Cat();
      }
   }

   /**
    * @Author: javafa
    * @Description: 查看动物的行为
    * @Date: 2024/7/31 17:22
    * @Param:
    * @return: void
    **/
   public void show() {
      animal.speak();
      animal.walk();
   }

}

4,调用测试


/**
 * @Author: javafa
 * @Description: 调用测试:查看动物园动物的行为
 * @Date: 2024/7/31 17:24
 * @Param:
 * @return: void
 **/
@Test
public void ZooShowTest(){
   //看看喵星人
   Zoo zoo = new Zoo("cat");
   zoo.show();
}


运行结果:

在这里插入图片描述


总结下,我们定义了抽象类Animal,然后定义了2个具体的猫(Cat)、狗(Dog)、继承Animal类,将相同的行为 走两步(walk) 在父类中直接实现,
而不同方式的自我介绍(speak)定义为抽象abstract方法,由子类去具体实现。

如果动物园中又来了牛啊,马啊,在Zoo中继续添加if-else就行了,如果来100个动物呢,

  • 修改100次?——> 就修改100次,写100个if-else,代码很清晰。
  • 那违反了开闭原则?——> 原则也不是必须的,代码很健壮

直到动物园来了一个团宠,小海豚,他只能游两步,没法走两步了,当然也简单,让海豚继承Animal后,我们可以体现多态性去重写Animal的walk方法。

  • 小海豚
/**
 * @Author: javafa
 * @Date: 2024/8/1 10:26
 * @Description: 动物-小海豚
 */
public class Dolphin extends Animal{

   @Override
   public void speak() {
      System.out.println("我是小海豚,我会海豚音!");
   }

   @Override
   public void walk() {
      System.out.println("我是小海豚,我不会走两步,我可以游两步!");
   }
}


  • 扩展Zoo

/**
 * @Author: javafa
 * @Date: 2024/7/31 16:04
 * @Description: 牛马们所在的动物园
 */
public class Zoo {

    Animal animal;//动物父类

    /**
     * @Author: javafa
     * @Description: 通过动物类型,来召唤(实例化)不同的动物
     * @Date: 2024/7/31 17:19
     * @Param: animalType
     * @return:
     **/
    public Zoo(String animalType) {
        if (animalType.equals("dog")) {
            animal = new Dog();
        } else if (animalType.equals("cat")) {
            animal = new Cat();
        } else if (animalType.equals("dolphin")){
            animal = new Dolphin();
        }
    }

    /**
     * @Author: javafa
     * @Description: 查看动物的行为
     * @Date: 2024/7/31 17:22
     * @Param:
     * @return: void
     **/
    public void show() {
        animal.speak();
        animal.walk();
    }

}

  • 调用测试

import com.fivemillion.algorithm.designpatterns.strategy.case2.Zoo;
import org.junit.jupiter.api.Test;

/**
 * @Author: javafa
 * @Date: 2024/7/30 16:04
 * @Description: 调用测试
 */
public class StrategyTest {

   /**
    * @Author: javafa
    * @Description: 调用测试:查看动物园动物的行为
    * @Date: 2024/7/31 17:24
    * @Param:
    * @return: void
    **/
   @Test
   public void ZooShowTest(){
      //看看小海豚
      Zoo zoo = new Zoo("dolphin");
      zoo.show();
   }

}

  • 运行结果:
    在这里插入图片描述

我们通过重写walk方法,成功解决了团宠-小海豚不能走两步的问题,如果动物园又来了小蜜蜂封,他也不能走两步,他只能飞两步,我们还得重写walk方法,
随着小动物的增多,和行为的增多,代码里全是没法共用的重写,显然通过继承没法 解决这个问题了。

总结一下继承Animal带来的问题

  1. 对于walk这种行为,如果定义抽象方法,那么像猫、狗等有相同走两步的动物,也要去实现walk,并且代码是相同的,就会导致大量重复代码,无法复用。
  2. 如果在父类中定义具体实现,具有不同行为的动物自己去重写,如小海豚,小蜜蜂,小海星,会导致大量的重写,而且小海豚,小海豹,小海狮他们的走两步都是通过
    游的方式,这部分重复的行为代码又无法复用。
  3. 如果我们继续增加一个吐泡泡的行为,那么父类Animal和所有的子类都要进行修改,即使有些动物并不能完成这个行为。

Interface接口

接下来看看java中接口如何解决这个问题。如果我们把走两步的行为抽象成接口Walk,那么对于猫、狗就可以实现这个接口,而小海豚不用实现这个接口。
把吐泡泡的行为抽象成接口Bubble,那么只有拥有吐泡泡行为能力小海豚来实现这个接口,以后来了小海狮也可以实现这个接口,而其他动物没有这个能力就不用实现了。

  • 接口方式UML类图

    在这里插入图片描述

Walk接口

定义走的接口方法

/**
 * @Author: javafa
 * @Date: 2024/8/1 13:24
 * @Description: 走的接口
 */
public interface Walk {
    /**
     * @Author: javafa
     * @Description: 走两步的方法
     * @Date: 2024/8/1 13:25
     * @Param:
     * @return: void
    **/
    void walk();
}

Bubble接口

定义吐泡泡的接口方法


/**
 * @Author: javafa
 * @Date: 2024/8/1 13:24
 * @Description: 吐泡泡的接口
 */
public interface Bubble {
    /**
     * @Author: javafa
     * @Description: 吐泡泡的方法
     * @Date: 2024/8/1 13:25
     * @Param:
     * @return: void
     **/
    void bubble();
}

Animal抽象类

只保留所有动物都有的自我介绍的speak抽象方法


/**
 * @Author: javafa
 * @Date: 2024/7/31 16:06
 * @Description: 动物类:别总牛马牛马的称呼,人家学名叫动物
 */
public abstract class Animal {

    /**
     * @Author: javafa
     * @Description: 每种动物 都要进自我介绍,由子类去具体实现
     * @Date: 2024/7/31 16:10
     * @Param:
     * @return: void
     **/
    public abstract void speak();


}

Dog类

继承Animal抽象类实现speak方法,实现Walk接口的walk方法


/**
 * @Author: javafa
 * @Date: 2024/7/31 16:24
 * @Description: 动物-大黄狗
 */
public class Dog extends Animal implements Walk{
    /**
     * @Author: zhaozuofa
     * @Description: 旺财说
     * @Date: 2024/7/31 16:38
     * @Param:
     * @return: void
    **/
    @Override
    public void speak() {
        System.out.println("旺财说:汪汪汪!");
    }

    @Override
    public void walk() {
        System.out.println("没事儿走两步");
    }
}

Cat类

继承Animal抽象类实现speak方法,实现Walk接口的walk方法


/**
 * @Author: javafa
 * @Date: 2024/7/31 16:24
 * @Description: 动物-猫
 */
public class Cat extends Animal implements Walk{
    @Override
    public void speak() {
        System.out.println("喵新人说:喵喵喵!");
    }

    @Override
    public void walk() {
        System.out.println("没事儿走两步");
    }
}

Dolphin类

继承Animal抽象类实现speak方法,实现Bubble接口的bubble方法


/**
 * @Author: javafa
 * @Date: 2024/8/1 10:26
 * @Description: 动物-小海豚
 */
public class Dolphin extends Animal implements Bubble{

    @Override
    public void speak() {
        System.out.println("我是小海豚,我会海豚音!");
    }


    @Override
    public void bubble() {
        System.out.println("我是小海豚,我会吐泡泡!");
    }
}

Zoo类

/**
 * @Author: javafa
 * @Date: 2024/7/31 16:04
 * @Description: 牛马们所在的动物园
 */
public class Zoo {

    Animal animal;//动物父类

    /**
     * @Author: javafa
     * @Description: 通过动物类型,来召唤(实例化)不同的动物
     * @Date: 2024/7/31 17:19
     * @Param: animalType
     * @return:
     **/
    public Zoo(String animalType) {
        if (animalType.equals("dog")) {
            animal = new Dog();
        } else if (animalType.equals("cat")) {
            animal = new Cat();
        } else if (animalType.equals("dolphin")){
            animal = new Dolphin();
        }
    }

    /**
     * @Author: javafa
     * @Description: 查看动物的行为
     * @Date: 2024/7/31 17:22
     * @Param:
     * @return: void
     **/
    public void show() {
        animal.speak();
        if(animal instanceof Dolphin){
            //有请小海豚表演
            Dolphin dolphin = (Dolphin) animal;
            dolphin.bubble();//小海豚吐泡泡
        }
    }

}

调用测试

欣赏小海豚的表演

import com.fivemillion.algorithm.designpatterns.strategy.case3.Zoo;
import org.junit.jupiter.api.Test;

/**
 * @Author: javafa
 * @Date: 2024/7/30 16:04
 * @Description: 调用测试
 */
public class StrategyTest {

    /**
     * @Author: javafa
     * @Description: 调用测试:查看动物园动物的行为
     * @Date: 2024/7/31 17:24
     * @Param:
     * @return: void
    **/
    @Test
    public void ZooShowTest(){
        //看看小海豚
        Zoo zoo = new Zoo("dolphin");
        zoo.show();
    }

}

运行结果
在这里插入图片描述


总结一下,我们虽然将自我介绍speak、走两步walk、吐泡泡bubble等行为,通过继承和实现给隔离分开,保证了没有某种行为的动物不必去拥有这项行为,如小海豚
不再走两步walk,阿猫阿狗不再吐泡泡bubble。但是对于walk接口来说,阿猫,阿狗走两步的行为是相同的,如果后续动物园来了100个动物也都是有走两步的行为,
我们就得写100次walk方法,导致这些代码无法复用,如果walk方法突然增加了一个参数,我们就要修改100个地方,继承中的问题仍然没有被解决。

导致我们如此纠结的本质原因是,对于walk来说,这是个不确定的行为,有的动物有,有的动物没有,甚至走两步也有不同的方式,有的动物用2条腿走,
有的动物用4条腿走,有的动物用8条腿走,万幸的是策略模式刚好可以解决这个问题。

策略模式

我们再来读一遍策略模式的定义:策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互换
策略模式使得算法可以在不影响客户端的情况下发生变化

回顾下设计原则核心思想

  1. 针对接口编程,而不是针对实现编程 。
  2. 将应用中可能需要变化的代码和不需要变化的代码分开独立。
  3. 都是为了交互对象间解耦合而操心。

针对接口编程,而不是针对实现编程,核心在于Animal类,walk走的行为应该作为一个Animal的变量,当然这个变量可以是接口Interface,也可以是抽象类Abstract,
实现了Animal类的子类,可以动态的选择为这个变量赋值去实现某个行为,如狗类中,就可以赋值4条腿去走,猫类中就可以赋值2条腿去走,小海豚就可以赋值不走,而走两步walk
和具体几条腿走就是策略模式的定义中被称为的“一些列算法”之一的算法,我们的赋值就是所谓的“互换”。这样就能使子类不是只绑定死某个接口或抽象类。


  • 走两步的UML类图

    在这里插入图片描述

针对Walk走两步的接口,我们进行了具体的实现,NonLegsWalk(没腿走)、TwoLegsWalk(2条腿走)、FourLegsWalk(4条腿走),如果后续有动物8条腿走,100条腿走
我们都可以达到灵活扩展,并且不会影响已有的实现。

Walk接口


/**
 * @Author: javafa
 * @Date: 2024/8/1 13:24
 * @Description: 走的接口
 */
public interface Walk {
    /**
     * @Author: javafa
     * @Description: 走两步的方法
     * @Date: 2024/8/1 13:25
     * @Param:
     * @return: void
    **/
    void walk();
}

没有腿走路-NonLegsWalk

/**
 * @Author: javafa
 * @Date: 2024/8/1 16:11
 * @Description: 走两步的具体实现类-没有腿走路
 */
public class NonLegsWalk implements Walk{

    @Override
    public void walk() {
        System.out.println("我没腿,我不走路!");
    }
}

2条腿走路-TwoLegsWalk


/**
 * @Author: javafa
 * @Date: 2024/8/1 16:11
 * @Description: 走两步的具体实现类-2条腿走路
 */
public class TwoLegsWalk implements Walk{

    @Override
    public void walk() {
        System.out.println("我用2条腿走路!");
    }
}

4条腿走路-FourLegsWalk


/**
 * @Author: javafa
 * @Date: 2024/8/1 16:11
 * @Description: 走两步的具体实现类-4条腿走路
 */
public class FourLegsWalk implements Walk{

    @Override
    public void walk() {
        System.out.println("我用4条腿走路!");
    }
}


Animal

Animal中我们将走两步的行为Walk被声明为接口类型的变量,在构造函数中初始化,由子类选择具体地走两步的实现方式,即接口的最终实现类


/**
 * @Author: javafa
 * @Date: 2024/7/31 16:06
 * @Description: 动物类:别总牛马牛马的称呼,人家学名叫动物
 */
public abstract class Animal {

    //走两步的行为被声明为接口类型的变量,在构造函数中初始化,由子类选择具体的走两步的实现方式,即接口的最终实现类
    public Walk walkObj;

    /**
     * @Author: javafa
     * @Description: 由子类去具体选择用什么方式进行走两步
     * @Date: 2024/8/1 16:41
     * @Param: walkImpl
     * @return:
    **/
    Animal(Walk walkImpl){
        this.walkObj = walkImpl;
    }

    protected Animal() {
    }

    /**
     * @Author: javafa
     * @Description: 每种动物 都要进自我介绍,由子类去具体实现
     * @Date: 2024/7/31 16:10
     * @Param:
     * @return: void
     **/
    public abstract void speak();

    /**
     * @Author: zhaozuofa
     * @Description: 实现walk方法,具体是由2条腿,4条腿等哪种walk实现来调用,依赖构造中的walkImpl具体实现
     * @Date: 2024/8/1 17:06
     * @Param:
     * @return: void
    **/
    public void walk(){
        if(walkObj != null){
            walkObj.walk();
        }
    }
}

Dolphin-小海豚

小海豚不会走两步,我们看Dolphin怎么做,其实什么也不做,对于Animal中接口类型的walk变量,子类不具备走两步的行为,不理会就行了,你怎么修改都对我没影响


/**
 * @Author: javafa
 * @Date: 2024/8/1 10:26
 * @Description: 动物-小海豚
 */
public class Dolphin extends Animal implements Bubble {

    @Override
    public void speak() {
        System.out.println("我是小海豚,我会海豚音!");
    }


    @Override
    public void bubble() {
        System.out.println("我是小海豚,我会吐泡泡!");
    }
}
  • 动物园-Zoo

动物园中我们可以正常展示动物的行为,自我介绍和走两步

/**
 * @Author: javafa
 * @Date: 2024/7/31 16:04
 * @Description: 牛马们所在的动物园
 */
public class Zoo {

    Animal animal;//动物父类

    /**
     * @Author: javafa
     * @Description: 通过动物类型,来召唤(实例化)不同的动物
     * @Date: 2024/7/31 17:19
     * @Param: animalType
     * @return:
     **/
    public Zoo(String animalType) {
        if (animalType.equals("dog")) {
            animal = new Dog();
        } else if (animalType.equals("cat")) {
            animal = new Cat();
        } else if (animalType.equals("dolphin")){
            animal = new Dolphin();
        }
    }

    /**
     * @Author: javafa
     * @Description: 查看动物的行为
     * @Date: 2024/7/31 17:22
     * @Param:
     * @return: void
     **/
    public void show() {
        animal.speak();
        animal.walk();
    }

}

  • 调用示例
import com.fivemillion.algorithm.designpatterns.strategy.case4.Zoo;
import org.junit.jupiter.api.Test;

/**
 * @Author: javafa
 * @Date: 2024/7/30 16:04
 * @Description: 调用测试
 */
public class StrategyTest {

    /**
     * @Author: javafa
     * @Description: 调用测试:查看动物园动物的行为
     * @Date: 2024/7/31 17:24
     * @Param:
     * @return: void
    **/
    @Test
    public void ZooShowTest(){
        //看看小海豚
        Zoo zoo = new Zoo("dolphin");
        zoo.show();
    }

}

  • 执行结果
    虽然在动物园的show()方法中,我们任然调用了animal.walk(); 但是由于Dolphin中我们并没有为父类的的Animal的walkObj变量赋值,
    所以Dolphin中walk()方法中,walkObj为null,所以不会调用walk()方法,所以不会走两步。

在这里插入图片描述

当然我们也可以通过为父类的walkObj变量赋值,来让Dolphin走两步,因为我们强大到预判了这类没腿的动物,预留了NonLegsWalk类,只需要稍稍修改Dolphin


/**
 * @Author: javafa
 * @Date: 2024/8/1 10:26
 * @Description: 动物-小海豚
 */
public class Dolphin extends Animal implements Bubble {

    
    public Dolphin() {
        //实现小海豚走两步的行为
        walkObj = new NonLegsWalk();
    }

    @Override
    public void speak() {
        System.out.println("我是小海豚,我会海豚音!");
    }


    @Override
    public void bubble() {
        System.out.println("我是小海豚,我会吐泡泡!");
    }
}
  • 运行结果

在这里插入图片描述


有一天,小海豚苦练走两步的技能,用他的鳍也可以走起来了,这时我们希望能动态的设置走两步,而不是在Dolphin的构造中写死走两步的实现类,其实也很简单,
为Animal的walkObj变量提供一个set方法,让外部可以去动态的设置走两步的实现类就行了

  • Animal

/**
 * @Author: javafa
 * @Date: 2024/7/31 16:06
 * @Description: 动物类:别总牛马牛马的称呼,人家学名叫动物
 */
public abstract class Animal {


    //走两步的行为被声明为接口类型的变量,在构造函数中初始化,由子类选择具体的走两步的实现方式,即接口的最终实现类
    public Walk walkObj;

    //提供set方法,可以更灵活的动态设置走两步的实现
    public void setWalkObj(Walk walkObj) {
        this.walkObj = walkObj;
    }

    /**
     * @Author: javafa
     * @Description: 由子类去具体选择用什么方式进行走两步
     * @Date: 2024/8/1 16:41
     * @Param: walkImpl
     * @return:
    **/
    Animal(Walk walkImpl){
        this.walkObj = walkImpl;
    }

    protected Animal() {
    }

    /**
     * @Author: javafa
     * @Description: 每种动物 都要进自我介绍,由子类去具体实现
     * @Date: 2024/7/31 16:10
     * @Param:
     * @return: void
     **/
    public abstract void speak();

    /**
     * @Author: zhaozuofa
     * @Description: 实现walk方法,具体是由2条腿,4条腿等哪种walk实现来调用,依赖构造中的walkImpl具体实现
     * @Date: 2024/8/1 17:06
     * @Param:
     * @return: void
    **/
    public void walk(){
        if(walkObj != null){
            walkObj.walk();
        }
    }
}

  • Zoo


/**
 * @Author: javafa
 * @Date: 2024/7/31 16:04
 * @Description: 牛马们所在的动物园
 */
public class Zoo {

    Animal animal;//动物父类

    /**
     * @Author: javafa
     * @Description: 通过动物类型,来召唤(实例化)不同的动物
     * @Date: 2024/7/31 17:19
     * @Param: animalType
     * @return:
     **/
    public Zoo(String animalType) {
        if (animalType.equals("dog")) {
            animal = new Dog();
        } else if (animalType.equals("cat")) {
            animal = new Cat();
        } else if (animalType.equals("dolphin")){
            animal = new Dolphin();
        }
    }

    /**
     * @Author: javafa
     * @Description: 查看动物的行为
     * @Date: 2024/7/31 17:22
     * @Param:
     * @return: void
     **/
    public void show() {
        animal.speak();
        //为小海豚动态设置走两步的方式-2条腿走
        animal.setWalkObj(new TwoLegsWalk());
        animal.walk();
    }

}

  • 运行结果

在这里插入图片描述


至此,策略模式已成,再次思考起开头朋友的总结“策略模式就是高级的if-else”,现在用装的话可以说,是也不是。相同点都是在面对不确定性的情况下,进行判断的抉择,
不同点是if-else更像是写好的人生剧本,因果注定。策略模式则是一种思想,面向接口编程而不是实现,他为每一种变化都提供一个入口,种一个种子,至于怎么
实现则完全由你,看到if-else你仿佛一眼看到生命的尽头,而看到策略模式仿佛看到了我命由我不由天的自由。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1967606.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

研0 冲刺算法竞赛 day26 P1803 凌乱的yyy / 线段覆盖

P1803 凌乱的yyy / 线段覆盖 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 考点&#xff1a;线段覆盖 思路&#xff1a;将整体结束时间进行排序&#xff0c;在从头开始遍历计数 代码&#xff1a; #include<iostream> #include <algorithm> using namespace …

从零开始学习机器学习,掌握AI未来的关键!

从零开始学习机器学习 1. 介绍1.1 人工智能&#xff08;AI&#xff09;概述1.2 机器学习在人工智能中的应用1.3 机器学习基础概念 2. 监督学习2.1 什么是监督学习2.2 回归分析2.3 分类问题2.4 模型评估和选择 3. 无监督学习3.1 什么是无监督学习3.2 聚类算法3.3 降维技术 4. 深…

Spring源码解析(27)之AOP的核心对象创建过程2

一、前言 我们在上一节中已经介绍了Advisor的创建过程&#xff0c;当时我们创建的logUtil这bean&#xff0c;他在 resolveBeforeInstantiation返回的是null&#xff0c;那么就会继续往下执行doCreateBean方法。 二、源码分析 protected Object doCreateBean(String beanName,…

永结无间Ⅸ--你不需要LLM Agent

人们将目光锁定在下一个闪亮的事物上。FOMO 是人性的一部分。这也适用于企业。就像数据科学成为每个企业分析功能的热潮一样&#xff0c;Agentic Architecture 是大多数 AI 雷达上的热门目标。 但您是否考虑过您是否真的需要它&#xff1f; 实际情况是&#xff0c;您不需要 A…

解答|一年期HTTPS证书如何获取?

自2023年年底以来&#xff0c;各大平台陆续下架了一年期免费HTTPS证书&#xff0c;目前市面上已经不再提供一年期的免费证书。付费正式版证书成为首选&#xff01;而DV证书由于其低廉的价格广受个人或者中小企业的青睐。 下面是DV类型证书&#xff08;13个月时长&#xff09;的…

防火墙Firewalld(iptables)

目录 一、Linux防火墙基础 1.什么是防火墙 2.防火墙的功能 3.防火墙的类型 二、Linux防火墙工具 1.iptables 2. netfilter 3.四表五链结构 3.1四表 3.2五链 3.3总结 4.数据包过滤的匹配流程 4.1规则表之间的顺序 4.2规则链之间的顺序 4.3规则链内的匹配顺序 …

人数管控系统助力图书馆实现精准客流统计分析

一、客流统计痛点在图书馆的日常运营中&#xff0c;客流统计面临着诸多难题。传统的人工计数方法不仅耗费人力&#xff0c;而且数据准确性难以保证。无法精确掌握不同时间段的读者流量&#xff0c;导致图书馆在资源配置和服务安排上缺乏科学依据。难以了解各个区域的受欢迎程度…

查看RAM和Flash

0 Preface/Foreword 1 查看方法 1.1 map文件中查看 1.1.1 RAM可用情况 在map文件中&#xff0c;搜索字符串&#xff1a;free_ramcp 该字段表示剩余可用的RAM大小&#xff0c;前面对应的是hexadecimal的数值&#xff08;单位Byte&#xff09;&#xff0c;就是剩余可用的RA…

浅谈ArkTS/ArkUI组件开发

浅谈ArkTS/ArkUI组件开发 本篇文章将从一个移动开发思维的维度出发&#xff0c;浅谈ArkTS组件开发的基础问题&#xff0c;比如状态管理、装饰器、属性传递、自定义构建函数、插槽、条件渲染&#xff0c;模块引用和路由跳转等。 创建项目 这里使用截图简单过一下&#xff0c;不…

数据结构与算法 - 递归

一、递归 1. 概述 定义&#xff1a;在计算机科学中&#xff0c;递归是一种解决计算问题的方法&#xff0c;其中解决方案取决于同一类问题的更小子集。 比如单链表递归遍历的例子&#xff1a; void f(Node node) {if(node null) {return;}println("before:" node…

Java 字符串常量池

目录 一、池化概念 二、字符串常量池 1. 概述 2. String对象的创建过程 1&#xff09;直接使用字符串常量进行赋值 2&#xff09;通过new创建String类对象 3&#xff09;结论 4&#xff09;intern方法 一、池化概念 先看如下的一段代码&#xff1a; String s1 "…

LLM实战系列(1)—强强联合Langchain-Vicuna应用实战

背景 本文主要介绍一下&#xff0c;基于Langchain与Vicuna-13B的外挂OceanBase知识库项目实战以及QA使用&#xff0c;项目地址: github.com/csunny/DB-G… 在开始之前&#xff0c;我们还是先看看效果&#xff5e; 自Meta发布LLaMA大模型以来&#xff0c; 围绕LLaMA微调的模型…

为什么越来越多的IT青年转行网络安全?

目前&#xff0c;我国互联网已经从爆发增长期进入平稳发展阶段&#xff0c;同时每年大量计算机相关专业的毕业生涌入就业市场&#xff0c;导致IT行业逐渐趋于饱和状态&#xff0c;甚至出现裁员现象&#xff0c;去年很多大厂都有裁员&#xff0c;不少程序员再就业成了难题。 面…

大彩触摸屏与单片机通讯

目录&#xff1a; 一、概述 1、触摸屏简介 2、安装软件 1&#xff09;设置VSPD软件 2&#xff09;设置VisualTFT软件 3&#xff09;设置串口软件 二、单片机发送指令给触摸屏 1、发送文本 2、显示与隐藏控件 1&#xff09;通过指令助手生成指令 2&#xff09;隐藏…

IDEA启动springBoot项目,显示构建和正在启动XxxApplication之后无反应

今天拉其他项目组的代码&#xff0c;然后发现IDEA启动不了项目&#xff0c;点击启动一闪而过&#xff0c;啥提示也没有&#xff0c;因为之前有过类似IDEA出错的经验&#xff0c;所以知道怎么排查。 首先打开IDEA日志输出&#xff0c;然后看具体是什么错 帮助>Tail Log in Co…

Linux用户无法访问Github怎么办?

进入Steam官网:Watt Toolkit 1.点击下载 2.在点击授权并下载 3.尽量选择Nas分流&#xff08;德国&#xff09; 4.然后选择最新版本 5.点击Linux版本它会自动文件夹 6.双击,他会自动下载 7.下载完成后进行解压,解压后进入目录 8.右键在此打开终端,在终端输入,运行此脚本 …

揭秘!焦虑症不只是心理战,这些躯体化症状你中招了吗?

引言 在这个快节奏、高压力的时代&#xff0c;焦虑症已成为许多人难以言说的秘密。它不仅悄无声息地侵蚀着我们的心理健康&#xff0c;还可能以一系列令人意想不到的躯体化症状显现&#xff0c;让人误以为自己只是“身体出了点小毛病”。今天&#xff0c;就让我们一起揭开焦虑…

[工具推荐]前端加解密之Burp插件Galaxy

如果觉得该文章有帮助的&#xff0c;麻烦师傅们可以搜索下微信公众号&#xff1a;良月安全。点个关注&#xff0c;感谢师傅们的支持。 免责声明 本号所发布的所有内容&#xff0c;包括但不限于信息、工具、项目以及文章&#xff0c;均旨在提供学习与研究之用。所有工具安全性…

肖扬率团队到北京军区干休所与离退休老干部座谈

在中国人民解放军建军97周年到来之际&#xff0c;为弘扬拥军优属光荣传统&#xff0c;营造尊崇关爱军人的浓厚氛围&#xff0c;世界中医药联合会骨伤科专业委员会副会长肖扬教授率团队遵从上级部门安排于7月31日上午到北京军区干休所看望离退休的老干部和多位老将军的后代&…

【DRF性能优化】

一、背景 项目中有一个查询脚本的接口&#xff0c;查询20条数据需要5min&#xff0c;性能很差,需要优化 二、问题排查 查看代码发现&#xff0c;serializers中&#xff0c;发现了一个奇怪的查询 查询脚本时&#xff0c;关联的脚本版本的一些字段也需要查询出来&#xff0c;…