欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java的23种设计模式,详细讲解(二)

程序员文章站 2023-11-23 08:05:34
本人免费整理了Java高级资料,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并发分布式等教程,一共30G,需要自己领取。传送门:https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q 1 ......

本人免费整理了java高级资料,涵盖了java、redis、mongodb、mysql、zookeeper、spring cloud、dubbo高并发分布式等教程,一共30g,需要自己领取。
传送门:https://mp.weixin.qq.com/s/jzddfh-7ynudmkjt0irl8q

1. 责任链(chain of responsibility)

intent

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。

class diagram

  • handler:定义处理请求的接口,并且实现后继链(successor)

 

Java的23种设计模式,详细讲解(二)

 

 

implementation

public abstract class handler {

    protected handler successor;


    public handler(handler successor) {
        this.successor = successor;
    }


    protected abstract void handlerequest(request request);
}
public class concretehandler1 extends handler {

    public concretehandler1(handler successor) {
        super(successor);
    }


    @override
    protected void handlerequest(request request) {
        if (request.gettype() == requesttype.type1) {
            system.out.println(request.getname() + " is handle by concretehandler1");
            return;
        }
        if (successor != null) {
            successor.handlerequest(request);
        }
    }
}
public class concretehandler2 extends handler {

    public concretehandler2(handler successor) {
        super(successor);
    }


    @override
    protected void handlerequest(request request) {
        if (request.gettype() == requesttype.type2) {
            system.out.println(request.getname() + " is handle by concretehandler2");
            return;
        }
        if (successor != null) {
            successor.handlerequest(request);
        }
    }
}
public class request {

    private requesttype type;
    private string name;


    public request(requesttype type, string name) {
        this.type = type;
        this.name = name;
    }


    public requesttype gettype() {
        return type;
    }


    public string getname() {
        return name;
    }
}
public enum requesttype {
    type1, type2
}
public class client {

    public static void main(string[] args) {

        handler handler1 = new concretehandler1(null);
        handler handler2 = new concretehandler2(handler1);

        request request1 = new request(requesttype.type1, "request1");
        handler2.handlerequest(request1);

        request request2 = new request(requesttype.type2, "request2");
        handler2.handlerequest(request2);
    }
}
request1 is handle by concretehandler1
request2 is handle by concretehandler2

 

jdk

2. 命令(command)

intent

将命令封装成对象中,具有以下作用:

  • 使用命令来参数化其它对象
  • 将命令放入队列中进行排队
  • 将命令的操作记录到日志中
  • 支持可撤销的操作

class diagram

  • command:命令
  • receiver:命令接收者,也就是命令真正的执行者
  • invoker:通过它来调用命令
  • client:可以设置命令与命令的接收者

 

Java的23种设计模式,详细讲解(二)

 

 

implementation

设计一个遥控器,可以控制电灯开关。

 

Java的23种设计模式,详细讲解(二)

 

 

public interface command {
    void execute();
}
public class lightoncommand implements command {
    light light;

    public lightoncommand(light light) {
        this.light = light;
    }

    @override
    public void execute() {
        light.on();
    }
}
public class lightoffcommand implements command {
    light light;

    public lightoffcommand(light light) {
        this.light = light;
    }

    @override
    public void execute() {
        light.off();
    }
}
public class light {

    public void on() {
        system.out.println("light is on!");
    }

    public void off() {
        system.out.println("light is off!");
    }
}
/**
 * 遥控器
 */
public class invoker {
    private command[] oncommands;
    private command[] offcommands;
    private final int slotnum = 7;

    public invoker() {
        this.oncommands = new command[slotnum];
        this.offcommands = new command[slotnum];
    }

    public void setoncommand(command command, int slot) {
        oncommands[slot] = command;
    }

    public void setoffcommand(command command, int slot) {
        offcommands[slot] = command;
    }

    public void onbuttonwaspushed(int slot) {
        oncommands[slot].execute();
    }

    public void offbuttonwaspushed(int slot) {
        offcommands[slot].execute();
    }
}
public class client {
    public static void main(string[] args) {
        invoker invoker = new invoker();
        light light = new light();
        command lightoncommand = new lightoncommand(light);
        command lightoffcommand = new lightoffcommand(light);
        invoker.setoncommand(lightoncommand, 0);
        invoker.setoffcommand(lightoffcommand, 0);
        invoker.onbuttonwaspushed(0);
        invoker.offbuttonwaspushed(0);
    }
}

 

jdk

3. 解释器(interpreter)

intent

为语言创建解释器,通常由语言的语法和语法分析来定义。

class diagram

  • terminalexpression:终结符表达式,每个终结符都需要一个 terminalexpression。
  • context:上下文,包含解释器之外的一些全局信息。

 

Java的23种设计模式,详细讲解(二)

 

 

implementation

以下是一个规则检验器实现,具有 and 和 or 规则,通过规则可以构建一颗解析树,用来检验一个文本是否满足解析树定义的规则。

例如一颗解析树为 d and (a or (b c)),文本 "d a" 满足该解析树定义的规则。

这里的 context 指的是 string。

public abstract class expression {
    public abstract boolean interpret(string str);
}
public class terminalexpression extends expression {

    private string literal = null;

    public terminalexpression(string str) {
        literal = str;
    }

    public boolean interpret(string str) {
        stringtokenizer st = new stringtokenizer(str);
        while (st.hasmoretokens()) {
            string test = st.nexttoken();
            if (test.equals(literal)) {
                return true;
            }
        }
        return false;
    }
}
public class andexpression extends expression {

    private expression expression1 = null;
    private expression expression2 = null;

    public andexpression(expression expression1, expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }

    public boolean interpret(string str) {
        return expression1.interpret(str) && expression2.interpret(str);
    }
}
public class orexpression extends expression {
    private expression expression1 = null;
    private expression expression2 = null;

    public orexpression(expression expression1, expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }

    public boolean interpret(string str) {
        return expression1.interpret(str) || expression2.interpret(str);
    }
}
public class client {

    /**
     * 构建解析树
     */
    public static expression buildinterpretertree() {
        // literal
        expression terminal1 = new terminalexpression("a");
        expression terminal2 = new terminalexpression("b");
        expression terminal3 = new terminalexpression("c");
        expression terminal4 = new terminalexpression("d");
        // b c
        expression alternation1 = new orexpression(terminal2, terminal3);
        // a or (b c)
        expression alternation2 = new orexpression(terminal1, alternation1);
        // d and (a or (b c))
        return new andexpression(terminal4, alternation2);
    }

    public static void main(string[] args) {
        expression define = buildinterpretertree();
        string context1 = "d a";
        string context2 = "a b";
        system.out.println(define.interpret(context1));
        system.out.println(define.interpret(context2));
    }
}
true
false

 

jdk

4. 迭代器(iterator)

intent

提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。

class diagram

  • aggregate 是聚合类,其中 createiterator() 方法可以产生一个 iterator;
  • iterator 主要定义了 hasnext() 和 next() 方法。
  • client 组合了 aggregate,为了迭代遍历 aggregate,也需要组合 iterator。

 

Java的23种设计模式,详细讲解(二)

 

 

implementation

public interface aggregate {
    iterator createiterator();
}
public class concreteaggregate implements aggregate {

    private integer[] items;

    public concreteaggregate() {
        items = new integer[10];
        for (int i = 0; i < items.length; i++) {
            items[i] = i;
        }
    }

    @override
    public iterator createiterator() {
        return new concreteiterator<integer>(items);
    }
}
public interface iterator<item> {

    item next();

    boolean hasnext();
}
public class concreteiterator<item> implements iterator {

    private item[] items;
    private int position = 0;

    public concreteiterator(item[] items) {
        this.items = items;
    }

    @override
    public object next() {
        return items[position++];
    }

    @override
    public boolean hasnext() {
        return position < items.length;
    }
}
public class client {

    public static void main(string[] args) {
        aggregate aggregate = new concreteaggregate();
        iterator<integer> iterator = aggregate.createiterator();
        while (iterator.hasnext()) {
            system.out.println(iterator.next());
        }
    }
}

 

jdk

5. 中介者(mediator)

intent

集中相关对象之间复杂的沟通和控制方式。

class diagram

  • mediator:中介者,定义一个接口用于与各同事(colleague)对象通信。
  • colleague:同事,相关对象

 

Java的23种设计模式,详细讲解(二)

 

 

implementation

alarm(闹钟)、coffeepot(咖啡壶)、calendar(日历)、sprinkler(喷头)是一组相关的对象,在某个对象的事件产生时需要去操作其它对象,形成了下面这种依赖结构:

 

Java的23种设计模式,详细讲解(二)

 

 

使用中介者模式可以将复杂的依赖结构变成星形结构:

 

Java的23种设计模式,详细讲解(二)

 

 

public abstract class colleague {
    public abstract void onevent(mediator mediator);
}
public class alarm extends colleague {

    @override
    public void onevent(mediator mediator) {
        mediator.doevent("alarm");
    }

    public void doalarm() {
        system.out.println("doalarm()");
    }
}
public class coffeepot extends colleague {
    @override
    public void onevent(mediator mediator) {
        mediator.doevent("coffeepot");
    }

    public void docoffeepot() {
        system.out.println("docoffeepot()");
    }
}
public class calender extends colleague {
    @override
    public void onevent(mediator mediator) {
        mediator.doevent("calender");
    }

    public void docalender() {
        system.out.println("docalender()");
    }
}
public class sprinkler extends colleague {
    @override
    public void onevent(mediator mediator) {
        mediator.doevent("sprinkler");
    }

    public void dosprinkler() {
        system.out.println("dosprinkler()");
    }
}
public abstract class mediator {
    public abstract void doevent(string eventtype);
}
public class concretemediator extends mediator {
    private alarm alarm;
    private coffeepot coffeepot;
    private calender calender;
    private sprinkler sprinkler;

    public concretemediator(alarm alarm, coffeepot coffeepot, calender calender, sprinkler sprinkler) {
        this.alarm = alarm;
        this.coffeepot = coffeepot;
        this.calender = calender;
        this.sprinkler = sprinkler;
    }

    @override
    public void doevent(string eventtype) {
        switch (eventtype) {
            case "alarm":
                doalarmevent();
                break;
            case "coffeepot":
                docoffeepotevent();
                break;
            case "calender":
                docalenderevent();
                break;
            default:
                dosprinklerevent();
        }
    }

    public void doalarmevent() {
        alarm.doalarm();
        coffeepot.docoffeepot();
        calender.docalender();
        sprinkler.dosprinkler();
    }

    public void docoffeepotevent() {
        // ...
    }

    public void docalenderevent() {
        // ...
    }

    public void dosprinklerevent() {
        // ...
    }
}
public class client {
    public static void main(string[] args) {
        alarm alarm = new alarm();
        coffeepot coffeepot = new coffeepot();
        calender calender = new calender();
        sprinkler sprinkler = new sprinkler();
        mediator mediator = new concretemediator(alarm, coffeepot, calender, sprinkler);
        // 闹钟事件到达,调用中介者就可以操作相关对象
        alarm.onevent(mediator);
    }
}
doalarm()
docoffeepot()
docalender()

 

dosprinkler()

jdk

6. 备忘录(memento)

intent

在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。

class diagram

  • originator:原始对象
  • caretaker:负责保存好备忘录
  • menento:备忘录,存储原始对象的的状态。备忘录实际上有两个接口,一个是提供给 caretaker 的窄接口:它只能将备忘录传递给其它对象;一个是提供给 originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 originator 访问本备忘录的内部状态。

 

Java的23种设计模式,详细讲解(二)

 

 

implementation

以下实现了一个简单计算器程序,可以输入两个值,然后计算这两个值的和。备忘录模式允许将这两个值存储起来,然后在某个时刻用存储的状态进行恢复。

实现参考:memento pattern - calculator example - java sourcecode

/**
 * originator interface
 */
public interface calculator {

    // create memento
    previouscalculationtocaretaker backuplastcalculation();

    // setmemento
    void restorepreviouscalculation(previouscalculationtocaretaker memento);

    int getcalculationresult();

    void setfirstnumber(int firstnumber);

    void setsecondnumber(int secondnumber);
}
/**
 * originator implementation
 */
public class calculatorimp implements calculator {

    private int firstnumber;
    private int secondnumber;

    @override
    public previouscalculationtocaretaker backuplastcalculation() {
        // create a memento object used for restoring two numbers
        return new previouscalculationimp(firstnumber, secondnumber);
    }

    @override
    public void restorepreviouscalculation(previouscalculationtocaretaker memento) {
        this.firstnumber = ((previouscalculationtooriginator) memento).getfirstnumber();
        this.secondnumber = ((previouscalculationtooriginator) memento).getsecondnumber();
    }

    @override
    public int getcalculationresult() {
        // result is adding two numbers
        return firstnumber + secondnumber;
    }

    @override
    public void setfirstnumber(int firstnumber) {
        this.firstnumber = firstnumber;
    }

    @override
    public void setsecondnumber(int secondnumber) {
        this.secondnumber = secondnumber;
    }
}
/**
 * memento interface to originator
 *
 * this interface allows the originator to restore its state
 */
public interface previouscalculationtooriginator {
    int getfirstnumber();
    int getsecondnumber();
}
/**
 *  memento interface to calculatoroperator (caretaker)
 */
public interface previouscalculationtocaretaker {
    // no operations permitted for the caretaker
}
/**
 * memento object implementation
 * <p>
 * note that this object implements both interfaces to originator and caretaker
 */
public class previouscalculationimp implements previouscalculationtocaretaker,
        previouscalculationtooriginator {

    private int firstnumber;
    private int secondnumber;

    public previouscalculationimp(int firstnumber, int secondnumber) {
        this.firstnumber = firstnumber;
        this.secondnumber = secondnumber;
    }

    @override
    public int getfirstnumber() {
        return firstnumber;
    }

    @override
    public int getsecondnumber() {
        return secondnumber;
    }
}
/**
 * caretaker object
 */
public class client {

    public static void main(string[] args) {
        // program starts
        calculator calculator = new calculatorimp();

        // assume user enters two numbers
        calculator.setfirstnumber(10);
        calculator.setsecondnumber(100);

        // find result
        system.out.println(calculator.getcalculationresult());

        // store result of this calculation in case of error
        previouscalculationtocaretaker memento = calculator.backuplastcalculation();

        // user enters a number
        calculator.setfirstnumber(17);

        // user enters a wrong second number and calculates result
        calculator.setsecondnumber(-290);

        // calculate result
        system.out.println(calculator.getcalculationresult());

        // user hits ctrl + z to undo last operation and see last result
        calculator.restorepreviouscalculation(memento);

        // result restored
        system.out.println(calculator.getcalculationresult());
    }
}
110
-273
110

 

jdk

  • java.io.serializable

7. 观察者(observer)

intent

定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。

主题(subject)是被观察的对象,而其所有依赖者(observer)称为观察者。

 

Java的23种设计模式,详细讲解(二)

 

 

class diagram

主题(subject)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的。

观察者(observer)的注册功能需要调用主题的 registerobserver() 方法。

 

Java的23种设计模式,详细讲解(二)

 

 

implementation

天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。

 

Java的23种设计模式,详细讲解(二)

 

 

public interface subject {
    void registerobserver(observer o);

    void removeobserver(observer o);

    void notifyobserver();
}
public class weatherdata implements subject {
    private list<observer> observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public weatherdata() {
        observers = new arraylist<>();
    }

    public void setmeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyobserver();
    }

    @override
    public void registerobserver(observer o) {
        observers.add(o);
    }

    @override
    public void removeobserver(observer o) {
        int i = observers.indexof(o);
        if (i >= 0) {
            observers.remove(i);
        }
    }

    @override
    public void notifyobserver() {
        for (observer o : observers) {
            o.update(temperature, humidity, pressure);
        }
    }
}
public interface observer {
    void update(float temp, float humidity, float pressure);
}
public class statisticsdisplay implements observer {

    public statisticsdisplay(subject weatherdata) {
        weatherdata.reisterobserver(this);
    }

    @override
    public void update(float temp, float humidity, float pressure) {
        system.out.println("statisticsdisplay.update: " + temp + " " + humidity + " " + pressure);
    }
}
public class currentconditionsdisplay implements observer {

    public currentconditionsdisplay(subject weatherdata) {
        weatherdata.registerobserver(this);
    }

    @override
    public void update(float temp, float humidity, float pressure) {
        system.out.println("currentconditionsdisplay.update: " + temp + " " + humidity + " " + pressure);
    }
}
public class weatherstation {
    public static void main(string[] args) {
        weatherdata weatherdata = new weatherdata();
        currentconditionsdisplay currentconditionsdisplay = new currentconditionsdisplay(weatherdata);
        statisticsdisplay statisticsdisplay = new statisticsdisplay(weatherdata);

        weatherdata.setmeasurements(0, 0, 0);
        weatherdata.setmeasurements(1, 1, 1);
    }
}
currentconditionsdisplay.update: 0.0 0.0 0.0
statisticsdisplay.update: 0.0 0.0 0.0
currentconditionsdisplay.update: 1.0 1.0 1.0
statisticsdisplay.update: 1.0 1.0 1.0

 

jdk

8. 状态(state)

intent

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。

class diagram

 

Java的23种设计模式,详细讲解(二)

 

 

implementation

糖果销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。

Java的23种设计模式,详细讲解(二)

 

public interface state {
    /**
     * 投入 25 分钱
     */
    void insertquarter();

    /**
     * 退回 25 分钱
     */
    void ejectquarter();

    /**
     * 转动曲柄
     */
    void turncrank();

    /**
     * 发放糖果
     */
    void dispense();
}
public class hasquarterstate implements state {

    private gumballmachine gumballmachine;

    public hasquarterstate(gumballmachine gumballmachine) {
        this.gumballmachine = gumballmachine;
    }

    @override
    public void insertquarter() {
        system.out.println("you can't insert another quarter");
    }

    @override
    public void ejectquarter() {
        system.out.println("quarter returned");
        gumballmachine.setstate(gumballmachine.getnoquarterstate());
    }

    @override
    public void turncrank() {
        system.out.println("you turned...");
        gumballmachine.setstate(gumballmachine.getsoldstate());
    }

    @override
    public void dispense() {
        system.out.println("no gumball dispensed");
    }
}
public class noquarterstate implements state {

    gumballmachine gumballmachine;

    public noquarterstate(gumballmachine gumballmachine) {
        this.gumballmachine = gumballmachine;
    }

    @override
    public void insertquarter() {
        system.out.println("you insert a quarter");
        gumballmachine.setstate(gumballmachine.gethasquarterstate());
    }

    @override
    public void ejectquarter() {
        system.out.println("you haven't insert a quarter");
    }

    @override
    public void turncrank() {
        system.out.println("you turned, but there's no quarter");
    }

    @override
    public void dispense() {
        system.out.println("you need to pay first");
    }
}
public class soldoutstate implements state {

    gumballmachine gumballmachine;

    public soldoutstate(gumballmachine gumballmachine) {
        this.gumballmachine = gumballmachine;
    }

    @override
    public void insertquarter() {
        system.out.println("you can't insert a quarter, the machine is sold out");
    }

    @override
    public void ejectquarter() {
        system.out.println("you can't eject, you haven't inserted a quarter yet");
    }

    @override
    public void turncrank() {
        system.out.println("you turned, but there are no gumballs");
    }

    @override
    public void dispense() {
        system.out.println("no gumball dispensed");
    }
}
public class soldstate implements state {

    gumballmachine gumballmachine;

    public soldstate(gumballmachine gumballmachine) {
        this.gumballmachine = gumballmachine;
    }

    @override
    public void insertquarter() {
        system.out.println("please wait, we're already giving you a gumball");
    }

    @override
    public void ejectquarter() {
        system.out.println("sorry, you already turned the crank");
    }

    @override
    public void turncrank() {
        system.out.println("turning twice doesn't get you another gumball!");
    }

    @override
    public void dispense() {
        gumballmachine.releaseball();
        if (gumballmachine.getcount() > 0) {
            gumballmachine.setstate(gumballmachine.getnoquarterstate());
        } else {
            system.out.println("oops, out of gumballs");
            gumballmachine.setstate(gumballmachine.getsoldoutstate());
        }
    }
}
public class gumballmachine {

    private state soldoutstate;
    private state noquarterstate;
    private state hasquarterstate;
    private state soldstate;

    private state state;
    private int count = 0;

    public gumballmachine(int numbergumballs) {
        count = numbergumballs;
        soldoutstate = new soldoutstate(this);
        noquarterstate = new noquarterstate(this);
        hasquarterstate = new hasquarterstate(this);
        soldstate = new soldstate(this);

        if (numbergumballs > 0) {
            state = noquarterstate;
        } else {
            state = soldoutstate;
        }
    }

    public void insertquarter() {
        state.insertquarter();
    }

    public void ejectquarter() {
        state.ejectquarter();
    }

    public void turncrank() {
        state.turncrank();
        state.dispense();
    }

    public void setstate(state state) {
        this.state = state;
    }

    public void releaseball() {
        system.out.println("a gumball comes rolling out the slot...");
        if (count != 0) {
            count -= 1;
        }
    }

    public state getsoldoutstate() {
        return soldoutstate;
    }

    public state getnoquarterstate() {
        return noquarterstate;
    }

    public state gethasquarterstate() {
        return hasquarterstate;
    }

    public state getsoldstate() {
        return soldstate;
    }

    public int getcount() {
        return count;
    }
}
public class client {

    public static void main(string[] args) {
        gumballmachine gumballmachine = new gumballmachine(5);

        gumballmachine.insertquarter();
        gumballmachine.turncrank();

        gumballmachine.insertquarter();
        gumballmachine.ejectquarter();
        gumballmachine.turncrank();

        gumballmachine.insertquarter();
        gumballmachine.turncrank();
        gumballmachine.insertquarter();
        gumballmachine.turncrank();
        gumballmachine.ejectquarter();

        gumballmachine.insertquarter();
        gumballmachine.insertquarter();
        gumballmachine.turncrank();
        gumballmachine.insertquarter();
        gumballmachine.turncrank();
        gumballmachine.insertquarter();
        gumballmachine.turncrank();
    }
}
you insert a quarter
you turned...
a gumball comes rolling out the slot...
you insert a quarter
quarter returned
you turned, but there's no quarter
you need to pay first
you insert a quarter
you turned...
a gumball comes rolling out the slot...
you insert a quarter
you turned...
a gumball comes rolling out the slot...
you haven't insert a quarter
you insert a quarter
you can't insert another quarter
you turned...
a gumball comes rolling out the slot...
you insert a quarter
you turned...
a gumball comes rolling out the slot...
oops, out of gumballs
you can't insert a quarter, the machine is sold out
you turned, but there are no gumballs
no gumball dispensed

 

9. 策略(strategy)

intent

定义一系列算法,封装每个算法,并使它们可以互换。

策略模式可以让算法独立于使用它的客户端。

class diagram

  • strategy 接口定义了一个算法族,它们都实现了 behavior() 方法。
  • context 是使用到该算法族的类,其中的 dosomething() 方法会调用 behavior(),setstrategy(strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 context 所使用的算法。

 

Java的23种设计模式,详细讲解(二)

 

 

与状态模式的比较

状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 context 所组合的 state 对象,而策略模式是通过 context 本身的决策来改变组合的 strategy 对象。所谓的状态转移,是指 context 在运行过程中由于一些条件发生改变而使得 state 对象发生改变,注意必须要是在运行过程中。

状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 context 使用的算法。

implementation

设计一个鸭子,它可以动态地改变叫声。这里的算法族是鸭子的叫声行为。

public interface quackbehavior {
    void quack();
}
public class quack implements quackbehavior {
    @override
    public void quack() {
        system.out.println("quack!");
    }
}
public class squeak implements quackbehavior{
    @override
    public void quack() {
        system.out.println("squeak!");
    }
}
public class duck {

    private quackbehavior quackbehavior;

    public void performquack() {
        if (quackbehavior != null) {
            quackbehavior.quack();
        }
    }

    public void setquackbehavior(quackbehavior quackbehavior) {
        this.quackbehavior = quackbehavior;
    }
}
public class client {

    public static void main(string[] args) {
        duck duck = new duck();
        duck.setquackbehavior(new squeak());
        duck.performquack();
        duck.setquackbehavior(new quack());
        duck.performquack();
    }
}
squeak!
quack!

 

jdk

  • java.util.comparator#compare()
  • javax.servlet.http.httpservlet
  • javax.servlet.filter#dofilter()

10. 模板方法(template method)

intent

定义算法框架,并将一些步骤的实现延迟到子类。

通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。

class diagram

 

Java的23种设计模式,详细讲解(二)

 

 

implementation

冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。

 

Java的23种设计模式,详细讲解(二)

 

 

public abstract class caffeinebeverage {

    final void preparerecipe() {
        boilwater();
        brew();
        pourincup();
        addcondiments();
    }

    abstract void brew();

    abstract void addcondiments();

    void boilwater() {
        system.out.println("boilwater");
    }

    void pourincup() {
        system.out.println("pourincup");
    }
}
public class coffee extends caffeinebeverage {
    @override
    void brew() {
        system.out.println("coffee.brew");
    }

    @override
    void addcondiments() {
        system.out.println("coffee.addcondiments");
    }
}
public class tea extends caffeinebeverage {
    @override
    void brew() {
        system.out.println("tea.brew");
    }

    @override
    void addcondiments() {
        system.out.println("tea.addcondiments");
    }
}
public class client {
    public static void main(string[] args) {
        caffeinebeverage caffeinebeverage = new coffee();
        caffeinebeverage.preparerecipe();
        system.out.println("-----------");
        caffeinebeverage = new tea();
        caffeinebeverage.preparerecipe();
    }
}
boilwater
coffee.brew
pourincup
coffee.addcondiments
-----------
boilwater
tea.brew
pourincup
tea.addcondiments

 

jdk

  • java.util.collections#sort()
  • java.io.inputstream#skip()
  • java.io.inputstream#read()
  • java.util.abstractlist#indexof()

11. 访问者(visitor)

intent

为一个对象结构(比如组合结构)增加新能力。

class diagram

  • visitor:访问者,为每一个 concreteelement 声明一个 visit 操作
  • concretevisitor:具体访问者,存储遍历过程中的累计结果
  • objectstructure:对象结构,可以是组合结构,或者是一个集合。

 

Java的23种设计模式,详细讲解(二)

 

 

implementation

public interface element {
    void accept(visitor visitor);
}
class customergroup {

    private list<customer> customers = new arraylist<>();

    void accept(visitor visitor) {
        for (customer customer : customers) {
            customer.accept(visitor);
        }
    }

    void addcustomer(customer customer) {
        customers.add(customer);
    }
}
public class customer implements element {

    private string name;
    private list<order> orders = new arraylist<>();

    customer(string name) {
        this.name = name;
    }

    string getname() {
        return name;
    }

    void addorder(order order) {
        orders.add(order);
    }

    public void accept(visitor visitor) {
        visitor.visit(this);
        for (order order : orders) {
            order.accept(visitor);
        }
    }
}
public class order implements element {

    private string name;
    private list<item> items = new arraylist();

    order(string name) {
        this.name = name;
    }

    order(string name, string itemname) {
        this.name = name;
        this.additem(new item(itemname));
    }

    string getname() {
        return name;
    }

    void additem(item item) {
        items.add(item);
    }

    public void accept(visitor visitor) {
        visitor.visit(this);

        for (item item : items) {
            item.accept(visitor);
        }
    }
}
public class item implements element {

    private string name;

    item(string name) {
        this.name = name;
    }

    string getname() {
        return name;
    }

    public void accept(visitor visitor) {
        visitor.visit(this);
    }
}
public interface visitor {
    void visit(customer customer);

    void visit(order order);

    void visit(item item);
}
public class generalreport implements visitor {

    private int customersno;
    private int ordersno;
    private int itemsno;

    public void visit(customer customer) {
        system.out.println(customer.getname());
        customersno++;
    }

    public void visit(order order) {
        system.out.println(order.getname());
        ordersno++;
    }

    public void visit(item item) {
        system.out.println(item.getname());
        itemsno++;
    }

    public void displayresults() {
        system.out.println("number of customers: " + customersno);
        system.out.println("number of orders:    " + ordersno);
        system.out.println("number of items:     " + itemsno);
    }
}
public class client {
    public static void main(string[] args) {
        customer customer1 = new customer("customer1");
        customer1.addorder(new order("order1", "item1"));
        customer1.addorder(new order("order2", "item1"));
        customer1.addorder(new order("order3", "item1"));

        order order = new order("order_a");
        order.additem(new item("item_a1"));
        order.additem(new item("item_a2"));
        order.additem(new item("item_a3"));
        customer customer2 = new customer("customer2");
        customer2.addorder(order);

        customergroup customers = new customergroup();
        customers.addcustomer(customer1);
        customers.addcustomer(customer2);

        generalreport visitor = new generalreport();
        customers.accept(visitor);
        visitor.displayresults();
    }
}
customer1
order1
item1
order2
item1
order3
item1
customer2
order_a
item_a1
item_a2
item_a3
number of customers: 2
number of orders:    4
number of items:     6

 

jdk

  • javax.lang.model.element.element and javax.lang.model.element.elementvisitor
  • javax.lang.model.type.typemirror and javax.lang.model.type.typevisitor

12. 空对象(null)

intent

使用什么都不做的空对象来代替 null。

一个方法返回 null,意味着方法的调用端需要去检查返回值是否是 null,这么做会导致非常多的冗余的检查代码。并且如果某一个调用端忘记了做这个检查返回值,而直接使用返回的对象,那么就有可能抛出空指针异常。

class diagram

 

Java的23种设计模式,详细讲解(二)

 

 

implementation

public abstract class abstractoperation {
    abstract void request();
}
public class realoperation extends abstractoperation {
    @override
    void request() {
        system.out.println("do something");
    }
}
public class nulloperation extends abstractoperation{
    @override
    void request() {
        // do nothing
    }
}
public class client {
    public static void main(string[] args) {
        abstractoperation abstractoperation = func(-1);
        abstractoperation.request();
    }

    public static abstractoperation func(int para) {
        if (para < 0) {
            return new nulloperation();
        }
        return new realoperation();
    }
}