设计模式-11种行为型

1.观察者模式

测试场景类:接收更新通知

public class TestClient {

    @Test
    public void test() {
        SubjectImpl subject = new SubjectImpl();
        IObserver IObserver1 = new IObserver1();
        IObserver IObserver2 = new IObserver2();
        IObserver IObserver3 = new IObserver3();

        subject.add(IObserver1);
        subject.add(IObserver2);
        subject.add(IObserver3);

        subject.change("疯魔状态");
        //输出结果:
        //主题状态改变:疯魔状态
        //我是观察者1,收到更新通知,状态为:疯魔状态
        //我是观察者2,收到更新通知,状态为:疯魔状态
        //我是观察者3,收到更新通知,状态为:疯魔状态
    }
}

抽象主题类:

public abstract class AbsSubject {

    private List<IObserver> list = new ArrayList<>();

    public void add(IObserver IObserver) {
        list.add(IObserver);
    }

    public void remove(IObserver IObserver) {
        list.remove(IObserver);
    }

    public void notifyAllObserver(String newState) {
        if (list.isEmpty()) return;
        for (IObserver IObserver : list) {
            IObserver.onNotify(newState);
        }
    }
}

具体主题类:

public class SubjectImpl extends AbsSubject {

    private String state;

    public String getState() {
        return state;
    }

    public void change(String newState) {
        System.out.println("主题状态改变:" + newState);
        this.state = newState;
        notifyAllObserver(newState);
    }
}

观察者接口:

public interface IObserver {

    void onNotify(String state);
}

具体观察者类:

public class IObserver1 implements IObserver {

    //观察者的状态
    private String observerState;

    @Override
    public void onNotify(String state) {
        this.observerState = state;
        System.out.println("我是观察者1,收到更新通知,状态为:" + state);
    }
}

2.责任链模式

测试场景类:各省事务处理

public class TestClient {

    @Test
    public void test() {
        //生成4个处理者
        Hunan hunan = new Hunan();
        Hubei hubei = new Hubei();
        Jiangxi jiangxi = new Jiangxi();
        Guangdong guangdong = new Guangdong();

        hunan.setNextHandler(hubei);//湖南处理不了,就交给湖北
        hubei.setNextHandler(jiangxi);//湖北处理不了,就交给江西
        jiangxi.setNextHandler(guangdong);//江西处理不了,就交给广东
        guangdong.setNextHandler(null);//广东处理不了,就没人可交了

        //湖南分别处理5个请求
        hunan.handleRequest("湖南");//输出:我是湖南处理中心,只处理湖南事务
        hunan.handleRequest("湖北");//输出:我是湖北处理中心,只处理湖北事务
        hunan.handleRequest("江西");//输出:我是江西处理中心,只处理江西事务
        hunan.handleRequest("广东");//输出:我是广东处理中心,只处理广东事务
        hunan.handleRequest("西藏");//输出:我是中国处理中心,处理各省处理不了的事务
    }

}

处理者接口:

public interface IHandler {

    void handleRequest(String request);
}

抽象处理者:

public class AbsHandler implements IHandler {

    private IHandler nextHandler;

    public IHandler getNextHandler() {
        return nextHandler;
    }

    public void setNextHandler(IHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    @Override
    public void handleRequest(String request) {

    }

    public void elseTodo(String request) {
        IHandler nextHandler = getNextHandler();
        if (nextHandler != null) {
            nextHandler.handleRequest(request);
        } else {
            superTodo(request);
        }
    }

    public void superTodo(String type) {
        System.out.println("我是中国处理中心,处理各省处理不了的事务");
    }
}

具体处理者:

public class Hunan extends AbsHandler {

    public static final String TYPE = "湖南";

    @Override
    public void handleRequest(String request) {
        if (request.equals(TYPE)) {
            System.out.println("我是" + request + "处理中心,只处理" + request + "事务");
        } else {
            elseTodo(request);
        }
    }

}

3.策略模式

测试场景类:会员折扣

public class TestClient {

    @Test
    public void test() {
        //创建策略类
        MemberStrategy strategy = new AdvancedMemberStrategy();
        //创建环境类
        Price price = new Price(strategy);
        //使用环境类
        double quote = price.quote(300);
        System.out.println("商品的优惠价为:" + quote);
        //输出结果:
        //对于高级会员的折扣为20%
        //商品的优惠价为:240.0
    }
}

策略接口类:

public interface MemberStrategy {

    /**
     * 计算优惠价
     *
     * @param price 原价
     * @return 优惠价
     */
    double calcPrice(double price);

}

环境角色类:

public class Price {

    private MemberStrategy strategy;

    public Price(MemberStrategy strategy) {
        this.strategy = strategy;
    }

    public double quote(double price) {
        return this.strategy.calcPrice(price);
    }

}

具体策略类:

/**
 * 高级会员策略
 * <p>
 * 作者:余天然 on 16/9/12 下午11:25
 */
public class AdvancedMemberStrategy implements MemberStrategy {
    @Override
    public double calcPrice(double price) {
        System.out.println("对于高级会员的折扣为20%");
        return price * 0.8;
    }
}

4.状态模式

测试场景类:投票系统

public class TestClient {

    /**
     * 同一个用户只能投一票,
     * 如果用户重复投票,则重复投的票无效
     * 如果投票次数超过5次,则判定为恶意刷票,取消他所投的票;
     * 如果投票次数超过8次,则被拉入黑名单,禁止再登录和使用系统
     */
    @Test
    public void test() {
        VoteContext voteContext = new VoteContext();
        for (int i = 0; i < 9; i++) {
            voteContext.vote("小明", "萌宝宝");
        }
        //输出结果:
        //恭喜投票成功
        //请不要重复投票
        //请不要重复投票
        //请不要重复投票
        //请不要重复投票
        //你有恶意刷屏行为,取消投票资格
        //你有恶意刷屏行为,取消投票资格
        //你有恶意刷屏行为,取消投票资格
        //小明被记录到黑名单中,将禁止登录和使用本系统
    }
}

环境类:

/**
 * 投票环境类
 * <p>
 * 作者:余天然 on 16/9/12 下午11:48
 */
public class VoteContext {

    private VoteState state;
    private Map<String, String> voteMap;//用户投票项
    private Map<String, Integer> voteCountMap;//用户投票次数

    public VoteContext() {
        voteMap = new HashMap<>();
        voteCountMap = new HashMap<>();
    }

    public Map<String, String> getVoteMap() {
        return voteMap;
    }

    /**
     * 投票
     *
     * @param user     投票人
     * @param voteItem 投票项
     */
    public void vote(String user, String voteItem) {
        //1.为该用户增加投票次数
        Integer oldVoteCount = voteCountMap.get(user);
        if (oldVoteCount == null) {
            oldVoteCount = 0;
        }
        oldVoteCount++;
        voteCountMap.put(user, oldVoteCount);

        //2.判断该用户的投票状态
        if (oldVoteCount == 1) {
            state = new NormalVoteState();
        } else if (oldVoteCount > 1 && oldVoteCount <=5) {
            state = new RepeatVoteState();
        } else if (oldVoteCount > 5 && oldVoteCount <=8) {
            state = new SpiteVoteState();
        } else if (oldVoteCount > 8) {
            state = new BlackVoteState();
        }
        state.vote(user, voteItem, this);
    }
}

状态接口:

/**
 * 投票状态类
 * <p>
 * 作者:余天然 on 16/9/12 下午11:46
 */
public interface VoteState {

    /**
     * 处理状态对应的行为
     *
     * @param user        投票人
     * @param voteItem    投票项
     * @param voteContext 投票上下文,用来在实现状态对应的功能处理的时候,可以回调上下文的数据
     */
    void vote(String user, String voteItem, VoteContext voteContext);
}

具体状态类:

/**
 * 正常投票状态
 * <p>
 * 作者:余天然 on 16/9/12 下午11:50
 */
public class NormalVoteState implements VoteState {
    @Override
    public void vote(String user, String voteItem, VoteContext voteContext) {
        //正常投票,记录到投票记录中
        voteContext.getVoteMap().put(user, voteItem);
        System.out.println("恭喜投票成功");
    }
}

5.命令模式

测试环境类:录音机

public class TestClient {

    /**
     * 小女孩茱丽(Julia)有一个盒式录音机,此录音机有播音(Play)、倒带(Rewind)和停止(Stop)功能,
     * 录音机的键盘便是请求者(Invoker)角色;茱丽(Julia)是客户端角色,而录音机便是接收者角色。
     * Command类扮演抽象命令角色,而PlayCommand、StopCommand和RewindCommand便是具体命令类。
     * 茱丽不需要知道播音、倒带和停止是怎么具体执行的,执行细节由键盘(Keypad)具体实现。
     * 茱丽只需要在键盘上按下相应的键便可以了
     */
    @Test
    public void test() {
        //创建接受者
        AudioPlayer audioPlayer = new AudioPlayer();

        //创建命令
        ICommand playCcommand = new PlayCommand(audioPlayer);
        ICommand rewindCommand = new RewindCommand(audioPlayer);
        ICommand stopCommand = new StopCommand(audioPlayer);

        //创建调用者
        Keypad keypad = new Keypad();
        keypad.setPlayCommand(playCcommand);
        keypad.setRewindCommand(rewindCommand);
        keypad.setStopCommand(stopCommand);

        //开始测试
        keypad.play();
        keypad.rewind();
        keypad.stop();
        keypad.play();

        //输出结果:
        //播放……
        //倒带……
        //停止……
        //播放……

    }
}

接受者类:

 */
public class AudioPlayer {

    public void play() {
        System.out.println("播放……");
    }

    public void rewind() {
        System.out.println("倒带……");
    }

    public void stop() {
        System.out.println("停止……");
    }
}

命令接口:

public interface ICommand {

    void execute();
}

调用者类:

public class Keypad {
    private ICommand playCommand;
    private ICommand rewindCommand;
    private ICommand stopCommand;

    public void setPlayCommand(ICommand playCommand) {
        this.playCommand = playCommand;
    }

    public void setRewindCommand(ICommand rewindCommand) {
        this.rewindCommand = rewindCommand;
    }

    public void setStopCommand(ICommand stopCommand) {
        this.stopCommand = stopCommand;
    }

    public void play() {
        playCommand.execute();
    }

    public void rewind() {
        rewindCommand.execute();
    }

    public void stop() {
        stopCommand.execute();
    }
}

具体命令:

public class PlayCommand implements ICommand {
    private AudioPlayer audioPlayer;

    public PlayCommand(AudioPlayer audioPlayer) {
        this.audioPlayer = audioPlayer;
    }

    @Override
    public void execute() {
        audioPlayer.play();
    }
}

6.模板方法模式

测试环境类:计算存款利息

public class TestClient {

    /**
     * 考虑一个计算存款利息的例子。
     * 假设系统需要支持两种存款账号,即货币市场(Money Market)账号和定期存款(Certificate of Deposite)账号。
     * 这两种账号的存款利息是不同的,因此,在计算一个存户的存款利息额时,必须区分两种不同的账号类型
     */
    @Test
    public void test() {
        AbsAccount marketAccount = new MoneyMarketAccount();
        System.out.println("货币市场账户的利息为:" + marketAccount.calcInterest());

        AbsAccount cdAccount = new CDAccount();
        System.out.println("定期存款账户的利息为:" + cdAccount.calcInterest());

        //输出结果:
        //货币市场账户的利息为:399.96
        //定期存款账户的利息为:533.28
    }
}

抽象模板角色:

public abstract class AbsAccount {

    /**
     * 计算利息
     *
     * @return
     */
    public final double calcInterest() {
        double interestRate = getInterestRate();
        String accountType = getAccountType();
        double account = calcAccount(accountType);
        return account * interestRate;
    }

    /**
     * 计算存款
     *
     * @param accountType
     * @return
     */
    private double calcAccount(String accountType) {
        //省略相关业务代码
        return 8888;
    }

    protected abstract String getAccountType();

    protected abstract double getInterestRate();
}

具体模板角色:

/**
 * 定期存款账户
 * <p>
 * 作者:余天然 on 16/9/13 上午12:59
 */
public class CDAccount extends AbsAccount{
    @Override
    protected String getAccountType() {
        return "Certificate of Deposite";
    }

    @Override
    protected double getInterestRate() {
        return 0.06;
    }
}

7.迭代子模式

测试场景类:自定义集合和迭代器

public class TestClient {

    /**
     * 自定义集合和迭代器
     */
    @Test
    public void test() {
        String[] strings = {"A", "B", "C", "D", "E"};
        Collection<String> collection = new CollectionImpl(strings);
        Iterator<String> iterator = collection.iterator();

        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        //输出结果:
        //A
        //B
        //C
        //D
        //E
    }
}

集合接口:

public interface Collection<T> {

    Iterator<T> iterator();

    T get(int i);

    int size();
}

迭代器接口:

public interface Iterator<T> {

    T previous();//前移

    T next();//后移

    T first();//取得第一个元素

    boolean hasNext();

}

具体集合类:

public class CollectionImpl implements Collection<String> {

    private String[] strings;

    public CollectionImpl(String[] strings) {
        this.strings = strings;
    }

    @Override
    public Iterator iterator() {
        return new IteratorImpl(this);
    }

    @Override
    public String get(int i) {
        return strings[i];
    }

    @Override
    public int size() {
        return strings.length;
    }
}

具体迭代器类:

public class IteratorImpl<T> implements Iterator<T> {

    private Collection<T> collection;
    private int pos = -1;

    public IteratorImpl(Collection<T> collection) {
        this.collection = collection;
    }

    @Override
    public T previous() {
        if (pos > 0) {
            pos--;
        }
        return collection.get(pos);
    }

    @Override
    public T next() {
        if (pos < collection.size() - 1) {
            pos++;
        }
        return collection.get(pos);
    }

    @Override
    public T first() {
        pos = 0;
        return collection.get(pos);
    }

    @Override
    public boolean hasNext() {
        if (pos < collection.size() - 1) {
            return true;
        } else {
            return false;
        }
    }
}
2016-10-20 10:5218