图解设计模式 --分开考虑

代码Github连接 :https://github.com/tangbi123/Tab-Design-Pattern

Bridge模式

将两样东西连接起来,它们分别是类的功能层次结构类的实现层次结构

类的层次结构的两个作用

1)希望增加新功能时

当腰增加新的功能时,我们可以从各个层次的类中找出最符合自己需求的类,然后以他为父类,编写子类,并在子类中增加新的功能。

2)希望增加新的实现

父类通过声明抽象方法来定义接口,子类实现抽象方法。
这里的类的层次接口并非用于增加功能,而是用于任务分担:

父类通过声明抽象方法来定义接口(API)
子类通过实现具体方法来实现接口(API)

1、示例

在这里插入图片描述
在这里插入图片描述

代码清单

1)DisPlayImpl

public abstract class DisplayImpl {
    public abstract void rawOpen();
    public abstract void rawPrin();
    public abstract void rawClose();
}

2)StringDisplayImpl

public class StringDisplayImpl extends DisplayImpl {
    private String string;
    private int width;

    public StringDisplayImpl(String string) {
        this.string = string;
        this.width = string.getBytes(StandardCharsets.UTF_8).length;
    }

    @Override
    public void rawOpen() {
        printLine();
    }

    @Override
    public void rawPrin() {
        System.out.println("|" + string + "|");
    }

    @Override
    public void rawClose() {
        printLine();
    }

    private void printLine(){
        System.out.print("+");
        for(int i = 0; i < width; i++){
            System.out.print("-");
        }
        System.out.println("+");
    }
}

3)Display

public class Display {
    private DisplayImpl impl;

    public Display(DisplayImpl impl) {
        this.impl = impl;
    }

    public void open(){
        impl.rawOpen();
    }
    public void print(){
        impl.rawPrin();
    }
    public void close(){
        impl.rawClose();
    }

    public final void display(){
        open();
        print();
        close();
    }
}
  1. CountDisplay
public class CountDisplay extends Display{

    public CountDisplay(DisplayImpl impl) {
        super(impl);
    }

    public void multiDisplay(int times){
        open();
        for(int i = 0; i < times; i++){
            print();
        }
        close();
    }
}

5)main

public class main {

    public static void main(String[] args) {
        Display d1 = new Display(new StringDisplayImpl("Hello, world"));

        Display d2 = new CountDisplay(new StringDisplayImpl("Hello, world1"));
        CountDisplay d3 = new CountDisplay(new StringDisplayImpl("Hello, world2"));

        d1.display();
        d2.display();
        d3.display();
        d3.multiDisplay(3);
    }
}

2、角色

在这里插入图片描述
1)Abstraction(抽象化) =》 Display
最上层,使用Implemenntor角色的方法定义了基本的功能,保存了Implementor角色的实例。
2)RefinedAbstraction(增加功能的抽象化) =》 CountDisplay
在Abstraction的基础上增加新的功能(继承)。
3)Implementor(实现者) =》 DisplayImpl
位于“类的实现层次结构”的最上层。定义了实现Abstraction角色接口的方法。
4)ConcreteImplementor(具体实现者) => StringDisplayImpl
负责实现 Implementor中的接口(API)

3、思路要点

分开后更能容易扩展

Bridge 的特征是 将 类的功能层次结构 和 类的实现层次结构 分离开来, 有利于对他们进行扩展。
当想要增加功能时,只需要在类的 功能层次结构 一侧增加类即可,不必对类的 实现层次结构 做任何修改。 而且,增加后的功能 可以被 所有的实现使用。

继承是强关联,委托是弱关联

Strategy模式

使用Strategy模式可以整体地替换算法的实现部分,能让我们轻松地以不同的算法去解决同一个问题。

1、示例

两种猜拳策略:
1、如果这局猜拳获胜了,那么下一句也出一样的手势。
2、根据上一句地手势从概率上计算出下一句地手势。
在这里插入图片描述
在这里插入图片描述

代码清单

1)Hand

public class Hand {
    public static final int HANDVALUE_GUU = 0; // 石头
    public static final int HANDVALUE_CHO = 1; // 剪刀
    public static final int HANDVALUE_PAA = 2; // 布

    public static final Hand[] hand = {
            new Hand(HANDVALUE_GUU),
            new Hand(HANDVALUE_CHO),
            new Hand(HANDVALUE_PAA)
    };
    private static final String[] name = {
            "石头", "剪刀", "布"
    };

    private int handValue;
    private Hand(int handValue){
        this.handValue = handValue;
    }
    public static Hand getHand(int handValue){
        return hand[handValue];
    }
    public boolean isStrongerThan(Hand h){
        return fight(h) == 1;
    }
    public boolean isWeakerThan(Hand h){
        return fight(h) == -1;
    }
    private int fight(Hand h){
        if(this == h)return 0;
        else if((this.handValue + 1) % 3 == h.handValue)
            return 1;
        else return 0;
    }
    public String toString(){
        return name[handValue];
    }
}

2)Strategy

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

3)WinnerStrategy

public class WinningStrategy implements Strategy{

    private Random random;
    private boolean won = false;
    private Hand preHand;
    public WinningStrategy(int seed){
        random = new Random(seed);
    }


    @Override
    public Hand nextHand() {
        if(!won){
            preHand = Hand.getHand(random.nextInt(3));
        }
        return preHand;
    }

    @Override
    public void study(boolean win) {
        won = win;
    }
}

4)ProbStrategy

public class ProbStrategy implements Strategy{

    private Random random;
    private int preHandValue = 0;
    private int currentValue = 0;
    private int[][] history = {
            {1,1,1},
            {1,1,1},
            {1,1,1}
    };
    public ProbStrategy(int seed){
        random = new Random(seed);
    }
    @Override
    public Hand nextHand() {
        int bet = random.nextInt(getSum(currentValue));
        int handValue = 0;
        if(bet < history[currentValue][0]){
            handValue = 0;
        }
        else if(bet < history[currentValue][0] + history[currentValue][1])
        {
            handValue  = 1;
        }
        else handValue = 2;

        preHandValue = currentValue;
        currentValue = 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;
    }
    @Override
    public void study(boolean win) {
        if(win){
            history[preHandValue][currentValue]++;
        }
        else{
            history[preHandValue][(currentValue + 1) % 3]++;
            history[preHandValue][(currentValue + 2) % 3]++;
        }
    }
}

5)Player

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 +
                '}';
    }
}

6)Main

public class StrategyMain {
    public static void main(String[] args) {
        if(args.length != 2){
            System.out.println("Usage: java main randomseed1 randomseed2");
            System.out.println("Example: java main 314 315");
            System.exit(0);
        }

        int seed1 = Integer.parseInt(args[0]);
        int seed2 = Integer.parseInt(args[1]);

        Player player1 = new Player("Taro", new WinningStrategy(seed1));
        Player player2 = new Player("Hana", new ProbStrategy(seed2));

        for(int i = 0; i < 100; 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: " + player2);
                player2.win();
                player1.lose();
            }
            else{
                System.out.println("Even ... ");
                player1.even();
                player2.even();
            }

        }

        System.out.println("Total results: ");
        System.out.println(player1.toString());
        System.out.println(player2.toString());
    }
}

2、角色

在这里插入图片描述
1)Strategy =》 Strategy接口
负责决定实现策略所必须地接口(API)。
2)ConcreteStrategy(具体决策类) =》WinnerStrategy, ProbStrategy
负责实现Strategy角色的接口(API),负责实现具体的策略。
3)Context(上下文) =》 Player
负责使用Stategy角色,Context角色保存了ConcreteStrategy角色的实例,并使用ConcreteStrategy角色去实现需求。

3、思路要点

为什么需要特意编写strategy角色

Strategy模式特意将 算法与其他部分分离开来, 只是定义了与算法相关的接口(API),然后再程序中以委托的方式来使用算法。
当我们想改善算法时,就不必修改Strategy角色的接口(API)了,仅仅修改ConcreteStrategy角色即可。 使用委托这种弱关联关系可以很方便地整体替换算法。

程序运行中也可以切换策略

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值