设计模式之策略模式(Java实现)

简介: 设计模式之策略模式(Java实现)

一、认识策略模式


策略模式定义:定义了算法族,将其封装起来,让它们直接可以互相替换,此模式的话变化独立于算法的使用者。把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。


结构:


抽象策略类:定义一个公共接口,各种不同的算法以不同过的形式来实现它,环境角色可使用这个接口来调用不同的算法。

具体策略类:实现了抽象策略类定义的接口,提供具体的算法实现。

环境类:持有一个策略类的引用,并最终给客户端使用。



优缺点:


优点:使用策略模式可避免多种条件语句;提供了一系列可重用的算法族;提供开闭原则,可在不修改代码情况下灵活增加新算法。

缺点:需要理解所有的策略算法区别,会造成很多的策略类,增加维护难度。

应用场景:


JDK中的Arrays.sort(T[] a, Comparator<? super T> c)方法,其中可以自定义使用Comparator接口来定义排序规则,这实际上也是一种策略模式体现。

Spring中的InstantiationStrategy接口包含了抽象实例化方法,用于创建实例,其实现类就实现了不同的创建方式有反射的、也有通过cglib方式的。


二、实现策略模式


2.1、 简单实现策略模式


demo见xyz.changlu.strategy.demo1包下代码:



抽象策略:Strategy


//抽象策略接口
public interface Strategy {
    void strategyMethod();
}


具体策略实现:ConcreteStrategyA、ConcreteStrategyB


//具体策略实现类A
public class ConcreteStrategyA implements Strategy{
    @Override
    public void strategyMethod() {
        System.out.println("具体策略类A实现算法....");
    }
}
//具体策略实现类B
public class ConcreteStrategyB implements Strategy {
    @Override
    public void strategyMethod() {
        System.out.println("具体策略实现类B执行算法....");
    }
}



指定环境类:Context


//指定环境类
public class Context {
    private Strategy strategy;//具体策略
    public Context(){
        //默认使用策略A
        this.strategy = new ConcreteStrategyA();
    }
    public Strategy getStrategy() {
        return strategy;
    }
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    //执行指定策略方法
    public void strategyMethod(){
        //通过调用指定的策略执行,可通过set/get方法更改策略
        strategy.strategyMethod();
    }
}



该环境可随意切换指定策略!

测试程序:测试类Customer


//测试类
public class Customer {
    public static void main(String[] args) {
        Context context = new Context();
        context.strategyMethod();
        //更改指定策略之后再次使用
        context.setStrategy(new ConcreteStrategyB());
        context.strategyMethod();
    }
}




2.2、实际小案例实现策略模式


案例描述:根据需求需要创建多种不同类型的僵尸,并且其外观、移动、攻击会不停的迭代更新,问如何设计会更好!


本案例来源于b站视频:2020年最详细的23种Java设计模式完整视频教程全集


第一版:



第二版:



说明:我们可以看到第二版中僵尸类型变多,并且其外观、移动、攻击都会有所不同,若是不使用策略设计模式可能就会像如下方式设计。


abstract class Zombie{
    abstract void describe();
    abstract void appearance();
    abstract void movie();
    abstract void attach();
}
//普通僵尸
class NormalZombie extends Zombie{
    void describe(){//类型描述
        ....
    }
    void appearance(){
        ....
    }
    void movie(){
        ....
    }
    void attach(){
        ....
    }
}
//大头僵尸
class NormalZombie extends Zombie{
    void describe(){//类型描述
        ....
    }
    void appearance(){
        ....
    }
    void movie(){
        ....
    }
    void attach(){
        ....
    }
}


我们看上面的这种方式设计,使用一个抽象类包含其三个特征,接着不同类型僵尸来继承抽象类并实现指定方法。

弊端描述:若是我们要更改某个僵尸的部分特征呢?需要回到原本代码中去更改嘛,这就违反了开闭原则了,并且若是用户想要自定义岂不是行不通了。


实现过程


解决方案:分析一下每个僵尸都有不同的类型,其类型、外观、移动、攻击方式这个抽象名词是固有的,其中的行为会发生改变,我们这样修改,对于抽象类中的固有抽象方法并不改变,多添加两个需要不断改变的特定特征,如移动、攻击方式单独定义一个接口,不同的移动行为、攻击方式来实现该接口即可,并且在僵尸类中添加几个对应移动、攻击方式的实例属性,并且能够进行修改与获取,在调用相对应方法时调用其实例的方法即可!


demo见xyz.changlu.stratege.demo2包目录下代码:



Attachable:抽象攻击接口。
Moveable:抽象移动接口。
Zombie:为僵尸抽象类。
说明:箭头指向的表示对应的实现类,仅作演示所以只对攻击方式、移动方式做了接口及实现类,其他暂不使用接口,演示到位即可。
抽象行为:Attachable、Moveable
//定义攻击接口
public interface Attachable {
    void attach();
}
//定义行为接口
public interface Moveable {
    void movie();
}


抽象僵尸类:Zombie


//僵尸抽象类
public abstract class Zombie {
    Attachable attachable;
    Moveable moveable;
    //对应的抽象方法
    abstract void describe();
    abstract void appearance();
    abstract void movie();
    abstract void attach();
    //初始化时具备指定能力
    public Zombie(Attachable attachable, Moveable moveable) {
        this.attachable = attachable;
        this.moveable = moveable;
    }
    public Attachable getAttachable() {
        return attachable;
    }
    public void setAttachable(Attachable attachable) {
        this.attachable = attachable;
    }
    public Moveable getMoveable() {
        return moveable;
    }
    public void setMoveable(Moveable moveable) {
        this.moveable = moveable;
    }
}


其中定义两个行为属性,并且包含set/get方法可进行切换设置行为属性。

定义了四个抽象方法分别为对应的不变的抽象行为。

具体行为:BiteAttach、HeadAttach、DirectionMove、StepToStepMove


//攻击行为实现类————————————————————————————————————————
//咬攻击
public class BiteAttach implements Attachable{
    @Override
    public void attach() {
        System.out.println("咬攻击方式!");
    }
}
//头部撞击攻击
public class HeadAttach implements Attachable{
    @Override
    public void attach() {
        System.out.println("头撞攻击");
    }
}
//移动行为实现类————————————————————————————————————————
//朝一个方向移动
public class DirectionMove implements Moveable {
    @Override
    public void movie() {
        System.out.println("朝着一个方法前进!");
    }
}
//一瘸一拐移动
public class StepToStepMove implements Moveable{
    @Override
    public void movie() {
        System.out.println("一撅一拐向前行进");
    }
}



具体僵尸类:NormalZombie、FlagZombie


//普通僵尸
public class NormalZombie extends Zombie {
    public NormalZombie() {
        //普通僵尸默认攻击为咬,移动方式为朝一个方向移动
        super(new BiteAttach(), new DirectionMove());
    }
    public NormalZombie(Attachable attachable, Moveable moveable) {
        super(attachable, moveable);
    }
    @Override
    void describe() {
        System.out.println("我是一个普通僵尸");
    }
    @Override
    void appearance() {
        System.out.println("一顶绿帽子");
    }
    @Override
    void movie() {
        moveable.movie();//指定指定行为接口方法
    }
    @Override
    void attach() {
        attachable.attach();
    }
}
//旗手僵尸
public class FlagZombie extends Zombie{
    public FlagZombie() {
        //普通僵尸默认攻击为咬,移动方式为一瘸一拐移动
        super(new BiteAttach(), new StepToStepMove());
    }
    public FlagZombie(Attachable attachable, Moveable moveable) {
        super(attachable, moveable);
    }
    @Override
    void describe() {
        System.out.println("我是一个旗帜僵尸");
    }
    @Override
    void appearance() {
        System.out.println("一顶绿帽子");
    }
    @Override
    void movie() {
        moveable.movie();
    }
    @Override
    void attach() {
        attachable.attach();
    }
}



测试程序:测试类Customer


//测试类
public class Customer {
    public static void main(String[] args) {
        //普通僵尸、旗帜僵尸的特征属性都来进行打印
        System.out.println("--------默认情况--------");
        NormalZombie normalZombie = new NormalZombie();
        printFeature(normalZombie);
        FlagZombie flagZombie = new FlagZombie();
        printFeature(flagZombie);
        //切换僵尸不同的特征,看僵尸的对应特征是否按照策略模式使用
        //普通僵尸的攻击方式改为头撞方式,旗帜僵尸的攻击方式改为头撞方式,行走方式改为朝一个方向移动
        System.out.println("--------修改指定的策略后--------");
        normalZombie.setAttachable(new HeadAttach());//更改普通僵尸
        flagZombie.setAttachable(new HeadAttach());//更改旗帜僵尸
        flagZombie.setMoveable(new DirectionMove());
        printFeature(normalZombie);
        printFeature(flagZombie);
    }
    //执行某个僵尸的所有动作
    public static void printFeature(Zombie zombie){
        zombie.describe();
        zombie.appearance();
        zombie.attach();
        zombie.movie();
        System.out.println();
    }
}




说明:通过策略模式我们可以自由的定义修改不同的行为,按照定义的策略执行方法!



总结


策略模式中定义了多个算法族,其定义一个接口包含抽象方法,不同的策略方式可以通过实现接口方法,让一个环境类持有对应该算法并且可进行随意改变策略使用!在游戏的角色装备中可以使用到对应策略模式,在Spring、JDK中也都有策略模式的应用。

相关文章
|
1月前
|
设计模式 算法 Kotlin
Kotlin - 改良设计模式 - 策略模式
Kotlin - 改良设计模式 - 策略模式
47 4
|
20天前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
22天前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
40 1
|
26天前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
29 2
|
1月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
36 4
|
1月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
45 2
|
2月前
|
设计模式 Java 程序员
[Java]23种设计模式
本文介绍了设计模式的概念及其七大原则,强调了设计模式在提高代码重用性、可读性、可扩展性和可靠性方面的作用。文章还简要概述了23种设计模式,并提供了进一步学习的资源链接。
52 0
[Java]23种设计模式
|
1月前
|
设计模式 JavaScript Java
Java设计模式:建造者模式详解
建造者模式是一种创建型设计模式,通过将复杂对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。本文详细介绍了建造者模式的原理、背景、应用场景及实际Demo,帮助读者更好地理解和应用这一模式。
|
1月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
3月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
下一篇
DataWorks