策略模式

模式定义:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式的变化独立于算法的使用者。

 案例:

 类图如下:

 

 

 如上所示,类图中抽象类定义了 三个抽象方法,分别对应三个动作:移动,攻击,展示,两个策略属性:攻击策略,移动策略。在具体的实现类(NormalZombie,FlagZombie,BigHeadZombie)中攻击和移动方法

使用了策略模式,具体攻击和移动方式,由策略属性的方法决定。可根据实际需要,对攻击和移动策略进行更换。

 

import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * 定义策略模式,使用类
 */
public class StartNew {
    public static void main(String[] args) {
        AbstractZombie zombie = new NormalAbstractZombie();
        /* 原来行为: 外表展示,攻击手段,移动方式  */
        zombie.display();
        zombie.move();
        System.out.println("------原始攻击策略------");
        zombie.attack();

        /* 更改攻击策略,使用已经定义的攻击策 */
        System.out.println("------第一次,更换攻击策略------");
        zombie.setAttackableStrategy(new HitAttack());
        zombie.attack();

        /* 再次更改攻击行为策略,使用匿名类添加没有的攻击策略 */
        System.out.println("------第二次,更换攻击策略------");
        zombie.setAttackableStrategy(new AttackableStrategy() {
            @Override
            public void attack() {
                System.out.println("匿名类自定义攻击策略:撕咬挠,全上!!!");
            }
        });
        /// 以上代码是为了说清楚,其实可用lambda简化:
        /// zombie.setAttackableStrategy(() -> System.out.println("撕咬挠,全上!!!"));
        zombie.attack();
    }
}

/**
 * 定义移动策略接口, 包含方法有move()方法
 */
interface MoveableStrategy {
    void move();
}

/**
 * 定义攻击策略接口, 包含方法有attack()方法
 */
interface AttackableStrategy {
    void attack();
}

/**
 * 僵尸(核心业务)抽象类
 * 整体抽象业务轮廓,定义公共属性、实现可共享方法,列出需要个性化的抽象方法
 */
@Data
@AllArgsConstructor
abstract class AbstractZombie {
    /** 移动策略对象 */
    MoveableStrategy moveableStrategy;
    /** 攻击策略对象 */
    AttackableStrategy attackableStrategy;

    /**
     * 展示
     */
    abstract void display();

    /**
     * 移动
     */
    abstract void move();

    /**
     * 攻击
     */
    abstract void attack();
}


/**
 * 普通僵尸
 * 定义抽象对象的名称,完成具体方法的重写
 */
class NormalAbstractZombie extends AbstractZombie {
    public NormalAbstractZombie() {
        super(new StepByStepMove(), new BiteAttack());
    }

    public NormalAbstractZombie(MoveableStrategy moveable, AttackableStrategy attackable) {
        super(moveable, attackable);
    }

    /**
     * 外观展现
     * 不变的内容,固定在具体实现类中
     */
    @Override
    public void display() {
        System.out.println("我是普通僵尸.");
    }

    /**
     * 移动
     * 属于策略模式中变的内容,留在移动策略实现类里实现,完成侧率变化
     */
    @Override
    void move() {
        moveableStrategy.move();
    }

    /**
     * 攻击
     * 属于策略模式中变的内容,留在攻击策略实现类里实现,完成侧率变化
     */
    @Override
    void attack() {
        attackableStrategy.attack();
    }
}


/**
 * 大头僵尸
 * 定义抽象对象的名称,完成具体方法的重写
 */
class BigHeadZombie extends AbstractZombie {
    public BigHeadZombie() {
        super(new StepByStepMove(), new BiteAttack());
    }

    public BigHeadZombie(MoveableStrategy moveable, AttackableStrategy attackable) {
        super(moveable, attackable);
    }

    /**
     * 外观展现
     * 不变的内容,固定在具体实现类中
     */
    @Override
    public void display() {
        System.out.println("我是大头僵尸.");
    }

    /**
     * 移动
     * 属于策略模式中变的内容,留在移动策略实现类里实现,完成侧率变化
     */
    @Override
    void move() {
        moveableStrategy.move();
    }

    /**
     * 攻击
     * 属于策略模式中变的内容,留在攻击策略实现类里实现,完成侧率变化
     */
    @Override
    void attack() {
        attackableStrategy.attack();
    }
}

/**
 * 骑手僵尸
 * 定义抽象对象的名称,完成具体方法的重写
 */
class FlagZombie extends AbstractZombie {
    public FlagZombie() {
        super(new StepByStepMove(), new BiteAttack());
    }

    public FlagZombie(MoveableStrategy moveable, AttackableStrategy attackable) {
        super(moveable, attackable);
    }

    /**
     * 外观展现
     * 不变的内容,固定在具体实现类中
     */
    @Override
    public void display() {
        System.out.println("我是旗手僵尸.");
    }

    /**
     * 移动
     * 属于策略模式中变的内容,留在移动策略实现类里实现,完成侧率变化
     */
    @Override
    void move() {
        moveableStrategy.move();
    }

    /**
     * 攻击
     * 属于策略模式中变的内容,留在攻击策略实现类里实现,完成侧率变化
     */
    @Override
    void attack() {
        attackableStrategy.attack();
    }
}

/**
 * 滚动走
 * 移动方式实现类, 具体实现 move() 方法
 */
class RollMove implements MoveableStrategy {
    @Override
    public void move() {
        System.out.println("系统定义好的移动策略实现:滚动");
    }
}

/**
 * 一步一步走
 * 移动方式实现类, 具体实现 move() 方法
 */
class StepByStepMove implements MoveableStrategy {
    @Override
    public void move() {
        System.out.println("系统定义好的移动策略实现:一步一步移动");
    }
}

/**
 * 口咬
 * 攻击方式实现类, 具体实现 attack() 方法
 */
class BiteAttack implements AttackableStrategy {
    @Override
    public void attack() {
        System.out.println("系统定义好的攻击策略实现:嘴咬");
    }
}

/**
 * 用手打
 * 第二种攻击方式实现类, 具体实现 attack() 方法
 */
class HitAttack implements AttackableStrategy {
    @Override
    public void attack() {
        System.out.println("系统定义好的攻击策略实现:手打");
    }
}

 

结果:

我是普通僵尸.
系统定义好的移动策略实现:一步一步移动
------原始攻击策略------
系统定义好的攻击策略实现:嘴咬
------第一次,更换攻击策略------
系统定义好的攻击策略实现:手打
------第二次,更换攻击策略------
匿名类自定义攻击策略:撕咬挠,全上!!!

 

 应用场景:

1.当你有很多类似的类,但它们执行某些行为的方式不同时,请使用此策略。
2.使用该模式将类的业务逻辑与算法的实现细节隔离开来,这些算法在逻辑上下文中可能不那么重要。
3.当你的类具有大量的条件运算符,并且在同一算法的不同变体之间切换时,请使用此模式。
优点:
1.可以将算法的实现细节与使用它的代码隔离开来。
2.符合开闭原则
Spring & JDK 源码中的应用:
1 java.util.Comparator
   根据数组对象,灵活制定排序策略
public class CompareTest491 {
    @Test
    public void test1(){
        String[] arr = new String[]{"AA","MM","GG","DD","KK","CC"};
        //将上述字符串数组从大到小排
        //由于默认的Arrays.sort()是调用String的compareTo()方法的(String实现了Comparable接口),而String的compareTo()方法是从小到大的,
        //要想临时进行一次从大到小的排序,可以在参数里面写一个Comparator的匿名实现类的匿名对象,然后重写compare方法,进而设置从大到小排
        Arrays.sort(arr, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return -o1.compareTo(o2);
            }
        });
        System.out.println(Arrays.toString(arr));
    }

    @Test
    public void test2(){
        Goods[] arr=new Goods[5];
        arr[0] = new Goods("lenovoMouse",34);
        arr[1] = new Goods("dellMouse",43);
arr[2] = new Goods("xiaomiMouse",12);
arr[3] = new Goods("huaweiMouse",65);
arr[4] = new Goods("microsoftMouse",43);
//这时如果想按照名称从低到高排序,再按照价格从高到低排序 //由于Goods类中的compareTo()方法的排序和想要的排序方式不一样,因此我们可以使用定制的排序 //因此在Arrays.sort()参数中new一个Comparator并重写compare()方法,实现想要的排序方式 Arrays.sort(arr, new Comparator<Goods>() { @Override public int compare(Goods o1, Goods o2) { if (o1.getName().equals(o2.getName())){ return -Double.compare(o1.getPrice(),o2.getPrice());//前面有个负号,表示从高到低排序 //一般情况下,String、包装类等重写的compareTo()或compare()方法都是从小到大排序的,所以想要从大到小排序的话需要在前面加"-" } else { return o1.getName().compareTo(o2.getName()); } } }); System.out.println(Arrays.toString(arr)); } }

 

2 org.springframework.beans.factory.support.InstantiationStrategy
 
 
 
posted on 2023-02-20 17:41  蔻德盈  阅读(24)  评论(0)    收藏  举报