精囊妙计 -- 策略模式(Strategy Pattern) 介绍 优缺点 使用场景案例及代码演示

一句话概括:

一个类的行为或算法可以在运行时更改。

补充介绍:

策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改,这种类型的设计模式属于行为型模式。

Strategy的意思是“策略”,指的是与敌军对垒时行军作战的方法。

在策略模式中,我们创建各种表示策略的对象一个行为随着策略对象改变而改变的context对象。策略对象改变context对象的执行算法。

定义一系列的算法,把策略对象一个个封装起来, 并且使它们可相互替换。

主要解决在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。

参与角色:

1)策略类的抽象基类(也可以是接口)拥有不同策略类的共有方法

2)各种策略实现类

3)Context类(持有策略基类的对象,可以动态随着策略对象的改变而改变行为)

优点:

1)算法可以自由切换。

2)避免使用多重条件判断。

3)扩展性良好。

缺点:

1)策略类会增多。

2)所有策略类都需要对外暴露。

使用案例或场景:

1) 诸葛亮的锦囊妙计,每一个锦囊就是一个策略。

2)旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。

3)JAVA AWT 中的 LayoutManager。

示例程序

需要源码的朋友可以前往github下载:

https://github.com/aharddreamer/chendong/tree/master/design-patterns/demo-code/design-patterns

程序简介:

下面这个程序的功能是让电脑玩猜拳游戏。我们考虑了两种猜拳策略,第一种策略是“如果这局获胜,那么下局也出一样的手势” (VinningStrategy),这是一种稍微有些笨的策略;另一种策略是“根据上一局的手势从概率上计算出下一局的手势” (ProbStrategy)。

示例程序类/接口一览:

Hand 表示猜拳游戏中的“手势”的类(工具)

Strategy 表示猜拳游戏中的策略的类 (策略类的基类)

WinningStrategy 表示“如果这局获胜,那么下局也出一样的手势” 这一策略的类 (具体策略对象1)

ProbStrategy 表示“根据上一局的手势从概率上计算出下一局的手势” 这一策略的类 (具体策略对象2)

Player 表示进行猜拳游戏的类 (Context环境类)

StrategyPatternTest 测试程序的类

 

代码:

public class Hand {
    public static final int SHI_TOU = 0; //表示石头的值
    public static final int JIAN_DAO = 1; //表示石头的值
    public static final int BU = 2; //表示石头的值
    public static final Hand[] hand = {
            new Hand(SHI_TOU), new Hand(JIAN_DAO), new Hand(BU)
    };
    public static final String[] name = {
            "石头", "剪刀", "布"
    };
    private int handValue;
    private Hand (int handValue) {
        this.handValue = handValue;
    }
    public boolean isStrongerThan(Hand hand) {
        return fight(hand) == -1;
    }
    public int fight(Hand hand) {
        if (this == hand) {
            return 0;
        }else if ((this.handValue + 1) % 3 == hand.handValue) {
            return 1;
        }else {
            return -1;
        }
    }
    public String toString() {
        return name[this.handValue];
    }
    public static Hand getHand(int handValue) {
        return hand[handValue];
    }
    public boolean isWeakerThan(Hand hand) {
        return fight(hand) == -1;
    }
}



public interface Strategy {
    Hand nextHand();
    void study(boolean vin);
}


public class WinningStrategy implements Strategy {
    private Random random;
    private boolean won = false;
    private Hand preHand;
    public WinningStrategy(int seed) {
        random = new Random(seed);
    }
    public Hand nextHand() {
        if (!won) {
            preHand = Hand.getHand(random.nextInt(3));
        }
        return preHand;
    }
    public void study(boolean win) {
        won = win;
    }
}

public class Player {
    private String name;
    private Strategy strategy;
    private int wincount;
    private int losecount;
    private int gamecount;
    //赋予姓名和策略
    public Player(String name, Strategy strategy) {
        this.name = name;
        this.strategy = strategy;
    }

    //策略决定下一句要出的手势
    public Hand nextHand() {
        return strategy.nextHand();
    }
    public void win() {
        strategy.study(true);
        wincount++;
        gamecount++;
    }
    public void lose() {
        strategy.study(false);
        losecount++;
        gamecount++;
    }
    public void even() {
        gamecount++;
    }

    @Override
    public String toString() {
        return "Player{" +
                "name='" + name + '\'' +
                ", strategy=" + strategy +
                ", wincount=" + wincount +
                ", losecount=" + losecount +
                ", gamecount=" + gamecount +
                '}';
    }
}


public class ProbStrategy implements Strategy {
    private Random random;
    private int preHandValue = 0;
    private int currentHandValue = 0;
    private int[][] history = {
            {1, 1, 1, },
            {1, 1, 1, },
            {1, 1, 1, },
    };
    public ProbStrategy(int seed) {
        random = new Random(seed);
    }
    public Hand nextHand() {
        int bet = random.nextInt(getSum(currentHandValue));
        int handValue = 0;
        if (bet < history[currentHandValue][0]) {
            handValue = 0;
        }else if (bet < history[currentHandValue][0] + history[currentHandValue][1]) {
            handValue = 1;
        }else {
            handValue = 2;
        }
        preHandValue = currentHandValue;
        currentHandValue = handValue;
        return Hand.getHand(handValue);
    }
    private int getSum(int hv) {
        int sum = 0;
        for (int i = 0; i < 3 ; i++) {
            sum += history[hv][i];
        }
        return sum;
    }
    public void  study(boolean win) {
        if (win) {
            history[preHandValue][currentHandValue] ++;
        }else {
            history[preHandValue][(currentHandValue + 1) % 3] ++;
            history[preHandValue][(currentHandValue + 2) % 3] ++;
        }
    }
}

public class StrategyPatternTest {
    public static void main(String[] args) {
        //可以选择动态确定seed
        /*if (args.length != 2) {
            System.out.println("Usage: java Main randomseed1 randomseed2");
            System.out.println("Example: java Main 314 15");
            System.exit(0);
        }
        int seed1 = Integer.parseInt(args[0]);
        int seed2 = Integer.parseInt(args[1]);*/
        int seed1 = 314;
        int seed2 = 15;
        Player player1 = new Player("WinningStrategyPlayer", new WinningStrategy(seed1));
        Player player2 = new Player("ProbStrategyPlayer", new ProbStrategy(seed2));
        for (int i = 0; i < 1000 ; i++) {
            Hand nextHand1 = player1.nextHand();
            Hand nextHand2 = player2.nextHand();
            if (nextHand1.isStrongerThan(nextHand2)) {
                System.out.println("Winner: " + player1);
                player1.win();
                player2.lose();
            }else if (nextHand2.isStrongerThan(nextHand1)) {
                System.out.println("Winner: " + nextHand2);
                player1.lose();
                player2.win();
            }else {
                System.out.println("Even...");
                player1.even();
                player2.even();
            }
        }
        System.out.println("Total Result: ");
        System.out.println(player1.toString());
        System.out.println(player2.toString());
    }
}

运行结果:

Winner: Player{name='WinningStrategyPlayer', strategy=org.cd.designpatterns.strategy.WinningStrategy@2ff4acd0, wincount=310, losecount=330, gamecount=993}

Winner: 石头

Winner: Player{name='WinningStrategyPlayer', strategy=org.cd.designpatterns.strategy.WinningStrategy@2ff4acd0, wincount=311, losecount=331, gamecount=995}

Even...

Winner: 石头

Even...

Even...

-------(省略若干行)---------

Total Result:

Player{name='WinningStrategyPlayer', strategy=org.cd.designpatterns.strategy.WinningStrategy@2ff4acd0, wincount=312, losecount=332, gamecount=1000}

Player{name='ProbStrategyPlayer', strategy=org.cd.designpatterns.strategy.ProbStrategy@54bedef2, wincount=332, losecount=312, gamecount=1000}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值