设计模式 - wtdig/study GitHub Wiki

设计模式

参考文档

一. 建造者模式(builder模式)

适合范围:组合的步骤一致,每个步骤的实现不一样

二. 原型模式

三、责任链模式

package com.duty;

/**
 * @author wb-wt261136
 * @version 2018/6/11. 15:55
 */
public abstract class AbstractHandleMessage {
    //定义的下一个处理者
    protected AbstractHandleMessage successor;
    //审批者姓名
    protected String leadName;

    public AbstractHandleMessage(String leadName) {

        this.leadName = leadName;
    }

    public void setSuccessor(AbstractHandleMessage successor) {
        this.successor = successor;
    }

    //请求处理方法
    public abstract void processRequest(Message request);
}


package com.duty;

/**
 * 员工请假信息类
 *
 * @author wb-wt261136
 * @version 2018/6/11. 15:52
 */
public class Message {
    private int count;


    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public Message(int count) {
        this.count = count;
    }
}


package com.duty;

/**
 * 主任处理
 *
 * @author wb-wt261136
 * @version 2018/6/11. 16:03
 */
public class Director extends AbstractHandleMessage {
    public Director(String leadName) {
        super(leadName);
    }

    @Override
    public void processRequest(Message request) {
        int count = request.getCount();
        if (count < 3) {
            System.out.println("主任:" + this.leadName + "审批假期了");
        } else {
            System.out.println("主任:" + this.leadName + "审批不了,转交申请");
            this.successor.processRequest(request);
        }
    }
}


package com.duty;

/**
 * 经理处理
 *
 * @author wb-wt261136
 * @version 2018/6/11. 16:11
 */
public class Manger extends AbstractHandleMessage {
    public Manger(String leadName) {
        super(leadName);
    }

    @Override
    public void processRequest(Message request) {
        int count = request.getCount();
        if (count > 3 && count < 10) {
            System.out.println("经理:" + this.leadName + "审批假期了");
        } else {
            System.out.println("经理:" + this.leadName + "审批不了,转交申请");
            this.successor.processRequest(request);
        }
    }
}


package com.duty;

/**
 * 总经理处理
 *
 * @author wb-wt261136
 * @version 2018/6/11. 16:14
 */
public class President extends AbstractHandleMessage {
    public President(String leadName) {
        super(leadName);
    }

    @Override
    public void processRequest(Message request) {
        int count = request.getCount();
        if (count > 10 && count < 30) {
            System.out.println("总经理:" + this.leadName + "审批假期了");
        } else {
            System.out.println("总经理:" + this.leadName + "拒绝请假");
        }
    }
}


package com.duty;

/**
 * 责任链测试
 *
 * @author wb-wt261136
 * @version 2018/6/11. 15:48
 */
public class DutyMainTest {
    /**
     * OA系统需要提供一个假条审批模块:如果员工请假天数小于3天,主任可以审批该假条;
     * 如果员工请假天数大于等于3天,小于10天,经理可以审批;
     * 如果员工请假天数大于等于10天,小于30天,总经理可以审批;
     * 如果超过30天,总经理也不能审批,提示相应的拒绝信息。
     * 试用职责链模式设计该假条审批模块。
     */

    public static void main(String[] args) {
        Message message = new Message(5);
        Director director = new Director("小明");
        Manger manger = new Manger("小红");
        President president = new President("小腿");
        director.setSuccessor(manger);
        manger.setSuccessor(president);
        director.processRequest(message);
    }
}

4、备忘录模式

package com.Forget;

/**
 * 象棋棋子类:原发器
 */

class Chessman {  
    private String label;  
    private int x;  
    private int y;  

    public Chessman(String label,int x,int y) {  
        this.label = label;  
        this.x = x;  
        this.y = y;  
    }  

    public void setLabel(String label) {  
        this.label = label;   
    }  

    public void setX(int x) {  
        this.x = x;   
    }  

    public void setY(int y) {  
        this.y = y;   
    }  

    public String getLabel() {  
        return (this.label);   
    }  

    public int getX() {  
        return (this.x);   
    }  

    public int getY() {  
        return (this.y);   
    }  

    //保存状态  
    public ChessmanMemento save() {  
        return new ChessmanMemento(this.label,this.x,this.y);  
    }  

    //恢复状态  
    public void restore(ChessmanMemento memento) {  
        this.label = memento.getLabel();  
        this.x = memento.getX();  
        this.y = memento.getY();  
    }  
}  


package com.Forget;

//象棋棋子备忘录类:备忘录
class ChessmanMemento {
    private String label;
    private int x;
    private int y;

    public ChessmanMemento(String label, int x, int y) {
        this.label = label;
        this.x = x;
        this.y = y;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public String getLabel() {
        return (this.label);
    }

    public int getX() {
        return (this.x);
    }

    public int getY() {
        return (this.y);
    }
}  


package com.Forget;

import java.util.ArrayList;
import java.util.List;

//象棋棋子备忘录管理类:负责人
class MementoCaretaker {
    //定义一个集合来存储多个备忘录
    private List mementolist = new ArrayList();

    public ChessmanMemento getMemento(int i) {
        return (ChessmanMemento) mementolist.get(i);
    }

    public void setMemento(ChessmanMemento memento) {
        mementolist.add(memento);
    }
}

package com.Forget;

class Client {
    private static int index = -1; //定义一个索引来记录当前状态所在位置
    private static MementoCaretaker mc = new MementoCaretaker();

    public static void main(String args[]) {
        Chessman chess = new Chessman("车", 1, 1);
        play(chess);
        chess.setY(4);
        play(chess);
        chess.setX(5);
        play(chess);
        undo(chess, index);
        undo(chess, index);
        redo(chess, index);
        redo(chess, index);
    }

    //下棋
    public static void play(Chessman chess) {
        mc.setMemento(chess.save()); //保存备忘录
        index++;
        System.out.println("棋子" + chess.getLabel() + "当前位置为:" + "第" + chess.getX() + "行" + "第" + chess.getY() + "列。");
    }

    //悔棋
    public static void undo(Chessman chess, int i) {
        System.out.println("******悔棋******");
        index--;
        chess.restore(mc.getMemento(i - 1)); //撤销到上一个备忘录
        System.out.println("棋子" + chess.getLabel() + "当前位置为:" + "第" + chess.getX() + "行" + "第" + chess.getY() + "列。");
    }

    //撤销悔棋
    public static void redo(Chessman chess, int i) {
        System.out.println("******撤销悔棋******");
        index++;
        chess.restore(mc.getMemento(i + 1)); //恢复到下一个备忘录
        System.out.println("棋子" + chess.getLabel() + "当前位置为:" + "第" + chess.getX() + "行" + "第" + chess.getY() + "列。");
    }
}

5、观察者模式

观察者模式是使用频率最高的设计模式之一,它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

观察者模式定义如下: 观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。

● Subject(目标):目标又称为主题,它是指被观察的对象。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify()。目标类可以是接口,也可以是抽象类或具体类。

● ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。 ● Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。

● ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法。通常在实现时,可以调用具体目标类的attach()方法将自己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。

观察者模式描述了如何建立对象与对象之间的依赖关系,以及如何构造满足这种需求的系统。观察者模式包含观察目标和观察者两类对象,一个目标可以有任意数目的与之相依赖的观察者,一旦观察目标的状态发生改变,所有的观察者都将得到通知。作为对这个通知的响应,每个观察者都将监视观察目标的状态以使其状态与目标状态同步,这种交互也称为发布-订阅(Publish-Subscribe)。观察目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅它并接收通知。 下面通过示意代码来对该模式进行进一步分析。首先我们定义一个抽象目标Subject,典型代码如下所示:

import java.util.*;  
abstract class Subject {  
    //定义一个观察者集合用于存储所有观察者对象  
protected ArrayList observers<Observer> = new ArrayList();  

//注册方法,用于向观察者集合中增加一个观察者  
    public void attach(Observer observer) {  
    observers.add(observer);  
}  

    //注销方法,用于在观察者集合中删除一个观察者  
    public void detach(Observer observer) {  
    observers.remove(observer);  
}  

    //声明抽象通知方法  
    public abstract void notify();  
}  
      具体目标类ConcreteSubject是实现了抽象目标类Subject的一个具体子类,其典型代码如下所示:
[java] view plain copy
class ConcreteSubject extends Subject {  
    //实现通知方法  
    public void notify() {  
        //遍历观察者集合,调用每一个观察者的响应方法  
        for(Object obs:observers) {  
            ((Observer)obs).update();  
        }  
    }     
}

抽象观察者角色一般定义为一个接口,通常只声明一个update()方法,为不同观察者的更新(响应)行为定义相同的接口,这个方法在其子类中实现,不同的观察者具有不同的响应方法。抽象观察者Observer典型代码如下所示:

interface Observer {  
    //声明响应方法  
    public void update();  
}  
      在具体观察者ConcreteObserver中实现了update()方法,其典型代码如下所示:
[java] view plain copy
class ConcreteObserver implements Observer {  
    //实现响应方法  
    public void update() {  
        //具体响应代码  
    }  
}

观察者模式在Java语言中的地位非常重要。在JDK的java.util包中,提供了Observable类以及Observer接口,它们构成了JDK对观察者模式的支持。

案例代码:

package com.observer;

import java.util.ArrayList;
import java.util.List;

//战队控制中心类:目标类
abstract class AllyControlCenter {
    protected String allyName; //战队名称  
    protected List<Observer> players = new ArrayList<Observer>(); //定义一个集合用于存储战队成员

    public void setAllyName(String allyName) {
        this.allyName = allyName;
    }

    public String getAllyName() {
        return this.allyName;
    }

    //注册方法  
    public void join(Observer obs) {
        System.out.println(obs.getName() + "加入" + this.allyName + "战队!");
        players.add(obs);
    }

    //注销方法  
    public void quit(Observer obs) {
        System.out.println(obs.getName() + "退出" + this.allyName + "战队!");
        players.remove(obs);
    }

    //声明抽象通知方法  
    public abstract void notifyObserver(String name);
}  
package com.observer;

//具体战队控制中心类:具体目标类
class ConcreteAllyControlCenter extends AllyControlCenter {
    public ConcreteAllyControlCenter(String allyName) {
        System.out.println(allyName + "战队组建成功!");
        System.out.println("----------------------------");
        this.allyName = allyName;
    }

    //实现通知方法  
    public void notifyObserver(String name) {
        System.out.println(this.allyName + "战队紧急通知,盟友" + name + "遭受敌人攻击!");
        //遍历观察者集合,调用每一个盟友(自己除外)的支援方法  
        for (Object obs : players) {
            if (!((Observer) obs).getName().equalsIgnoreCase(name)) {
                ((Observer) obs).help();
            }
        }
    }
}
package com.observer;

//抽象观察类
interface Observer {  
    public String getName();  
    public void setName(String name);  
    public void help(); //声明支援盟友方法  
    public void beAttacked(AllyControlCenter acc); //声明遭受攻击方法  
}  
package com.observer;

//战队成员类:具体观察者类
class Player implements Observer {  
    private String name;  

    public Player(String name) {  
        this.name = name;  
    }  

    public void setName(String name) {  
        this.name = name;  
    }  

    public String getName() {  
        return this.name;  
    }  

    //支援盟友方法的实现  
    public void help() {  
        System.out.println("坚持住," + this.name + "来救你!");  
    }  

    //遭受攻击方法的实现,当遭受攻击时将调用战队控制中心类的通知方法notifyObserver()来通知盟友  
    public void beAttacked(AllyControlCenter acc) {  
        System.out.println(this.name + "被攻击!");  
        acc.notifyObserver(name);         
    }  
}  
package com.observer;

class Client {
    public static void main(String args[]) {
        //定义观察目标对象  
        AllyControlCenter acc;
        acc = new ConcreteAllyControlCenter("金庸群侠");

        //定义四个观察者对象  
        Observer player1, player2, player3, player4;

        player1 = new Player("杨过");
        acc.join(player1);

        player2 = new Player("令狐冲");
        acc.join(player2);

        player3 = new Player("张无忌");
        acc.join(player3);

        player4 = new Player("段誉");
        acc.join(player4);

        //某成员遭受攻击  
        player1.beAttacked(acc);
    }
}

6、策略模式

在策略模式中,我们可以定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法,在这里,每一个封装算法的类我们都可以称之为一种策略(Strategy),为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做规则的定义,而每种算法则对应于一个具体策略类。 策略模式的主要目的是将算法的定义与使用分开,也就是将算法的行为和环境分开,将算法的定义放在专门的策略类中,每一个策略类封装了一种实现算法,使用算法的环境类针对抽象策略类进行编程,符合“依赖倒转原则”。在出现新的算法时,只需要增加一个新的实现了抽象策略类的具体策略类即可。策略模式定义如下: 策略模式(Strategy Pattern):定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为型模式。

在策略模式结构图中包含如下几个角色: ● Context(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。 ● Strategy(抽象策略类):它为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。 ● ConcreteStrategy(具体策略类):它实现了在抽象策略类中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。

package com.arithmetic;

//电影票类:环境类
class MovieTicket {
    private double price;
    private Discount discount; //维持一个对抽象折扣类的引用  

    public void setPrice(double price) {
        this.price = price;
    }

    //注入一个折扣类对象  
    public void setDiscount(Discount discount) {
        this.discount = discount;
    }

    public double getPrice() {
        //调用折扣类的折扣价计算方法  
        return discount.calculate(this.price);
    }
}  


package com.arithmetic;

//折扣类:抽象策略类
interface Discount {
    public double calculate(double price);
} 


package com.arithmetic;

//儿童票折扣类:具体策略类
class ChildrenDiscount implements Discount {
    public double calculate(double price) {
        System.out.println("儿童票:");
        return price - 10;
    }
}   


package com.arithmetic;

//学生票折扣类:具体策略类
class StudentDiscount implements Discount {
    public double calculate(double price) {
        System.out.println("学生票:");
        return price * 0.8;
    }
}   

package com.arithmetic;

/**
 * @author wb-wt261136
 * @version 2018/6/13. 10:57
 */
public class DiscountMain {
    public static void main(String[] args) {
        Double originalPrice = 60.0;
        MovieTicket movieTicket = new MovieTicket();
        movieTicket.setPrice(originalPrice);
        ChildrenDiscount childrenDiscount = new ChildrenDiscount();
        movieTicket.setDiscount(childrenDiscount);
        System.out.println(movieTicket.getPrice());
    }
}

7、模板方法模式

模板方法模式是结构最简单的行为型设计模式,在其结构中只存在父类与子类之间的继承关系。通过使用模板方法模式,可以将一些复杂流程的实现步骤封装在一系列基本方法中,在抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。模板方法模式提供了一个模板方法来定义算法框架,而某些具体步骤的实现可以在其子类中完成。

package com.template;

/**
 * @author wb-wt261136
 * @version 2018/6/13. 14:17
 */
public abstract class AbstractShopping {

    public void shopping() {
        going();
        buy();
        pay();
    }

    public void going() {
        System.out.println("打车来到商场");
    }

    public abstract void buy();

    public void pay() {
        System.out.println("进行付钱");
    }

}


package com.template;

/**
 * @author wb-wt261136
 * @version 2018/6/13. 14:23
 */
public class BigShopping extends AbstractShopping {
    @Override
    public void buy() {
        System.out.println("买了很多东西");
    }
}

package com.template;

/**
 * @author wb-wt261136
 * @version 2018/6/13. 14:24
 */
public class SmallShopping extends AbstractShopping {
    @Override
    public void buy() {
        System.out.println("买了很少东西");
    }
}


package com.template;

/**
 * @author wb-wt261136
 * @version 2018/6/13. 14:24
 */
public class ShoppingMain {
    public static void main(String[] args) {
        BigShopping bigShopping = new BigShopping();
        bigShopping.shopping();
    }
}

8、访问者模式

访问者模式是一种较为复杂的行为型设计模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。例如处方单中的各种药品信息就是被访问的元素,而划价人员和药房工作人员就是访问者。访问者模式使得用户可以在不修改现有系统的情况下扩展系统的功能,为这些不同类型的元素增加新的操作。+

在使用访问者模式时,被访问元素通常不是单独存在的,它们存储在一个集合中,这个集合被称为“对象结构”,访问者通过遍历对象结构实现对其中存储的元素的逐个操作。

package com.visitor;

//员工类:抽象元素类
interface Employee {
    void accept(Department handler); //接受一个抽象访问者访问
}  

package com.visitor;

import java.util.ArrayList;
import java.util.List;

//员工列表类:对象结构
class EmployeeList {
    //定义一个集合用于存储员工对象  
    private List<Employee> list = new ArrayList<Employee>();

    public void addEmployee(Employee employee) {
        list.add(employee);
    }

    //遍历访问员工集合中的每一个员工对象  
    public void accept(Department handler) {
        for (Object obj : list) {
            ((Employee) obj).accept(handler);
        }
    }
}

package com.visitor;

//部门类:抽象访问者类
abstract class Department {
    //声明一组重载的访问方法,用于访问不同类型的具体元素  
    public abstract void visit(FulltimeEmployee employee);

    public abstract void visit(ParttimeEmployee employee);
}  

package com.visitor;

//全职员工类:具体元素类
class FulltimeEmployee implements Employee {
    private String name;
    private double weeklyWage;
    private int workTime;

    public FulltimeEmployee(String name, double weeklyWage, int workTime) {
        this.name = name;
        this.weeklyWage = weeklyWage;
        this.workTime = workTime;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setWeeklyWage(double weeklyWage) {
        this.weeklyWage = weeklyWage;
    }

    public void setWorkTime(int workTime) {
        this.workTime = workTime;
    }

    public String getName() {
        return (this.name);
    }

    public double getWeeklyWage() {
        return (this.weeklyWage);
    }

    public int getWorkTime() {
        return (this.workTime);
    }

    public void accept(Department handler) {
        handler.visit(this); //调用访问者的访问方法  
    }
}  

package com.visitor;

//兼职员工类:具体元素类
class ParttimeEmployee implements Employee {
    private String name;
    private double hourWage;
    private int workTime;

    public ParttimeEmployee(String name, double hourWage, int workTime) {
        this.name = name;
        this.hourWage = hourWage;
        this.workTime = workTime;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setHourWage(double hourWage) {
        this.hourWage = hourWage;
    }

    public void setWorkTime(int workTime) {
        this.workTime = workTime;
    }

    public String getName() {
        return (this.name);
    }

    public double getHourWage() {
        return (this.hourWage);
    }

    public int getWorkTime() {
        return (this.workTime);
    }

    public void accept(Department handler) {
        handler.visit(this); //调用访问者的访问方法  
    }
}  

package com.visitor;

//财务部类:具体访问者类
class FADepartment extends Department {
    //实现财务部对全职员工的访问  
    public void visit(FulltimeEmployee employee) {
        int workTime = employee.getWorkTime();
        double weekWage = employee.getWeeklyWage();
        if (workTime > 40) {
            weekWage = weekWage + (workTime - 40) * 100;
        } else if (workTime < 40) {
            weekWage = weekWage - (40 - workTime) * 80;
            if (weekWage < 0) {
                weekWage = 0;
            }
        }
        System.out.println("正式员工" + employee.getName() + "实际工资为:" + weekWage + "元。");
    }

    //实现财务部对兼职员工的访问  
    public void visit(ParttimeEmployee employee) {
        int workTime = employee.getWorkTime();
        double hourWage = employee.getHourWage();
        System.out.println("临时工" + employee.getName() + "实际工资为:" + workTime * hourWage + "元。");
    }
}  

package com.visitor;

import java.util.ArrayList;
import java.util.List;

//人力资源部类:具体访问者类
class HRDepartment extends Department {
    //实现人力资源部对全职员工的访问  
    public void visit(FulltimeEmployee employee) {
        int workTime = employee.getWorkTime();
        System.out.println("正式员工" + employee.getName() + "实际工作时间为:" + workTime + "小时。");
        if (workTime > 40) {
            System.out.println("正式员工" + employee.getName() + "加班时间为:" + (workTime - 40) + "小时。");
        } else if (workTime < 40) {
            System.out.println("正式员工" + employee.getName() + "请假时间为:" + (40 - workTime) + "小时。");
        }
    }

    //实现人力资源部对兼职员工的访问  
    public void visit(ParttimeEmployee employee) {
        int workTime = employee.getWorkTime();
        System.out.println("临时工" + employee.getName() + "实际工作时间为:" + workTime + "小时。");
    }
}

package com.visitor;

class Client {
    public static void main(String args[]) {
        EmployeeList list = new EmployeeList();
        Employee fte1, fte2, fte3, pte1, pte2;

        fte1 = new FulltimeEmployee("张无忌", 3200.00, 45);
        fte2 = new FulltimeEmployee("杨过", 2000.00, 40);
        fte3 = new FulltimeEmployee("段誉", 2400.00, 38);
        pte1 = new ParttimeEmployee("洪七公", 80.00, 20);
        pte2 = new ParttimeEmployee("郭靖", 60.00, 18);

        list.addEmployee(fte1);
        list.addEmployee(fte2);
        list.addEmployee(fte3);
        list.addEmployee(pte1);
        list.addEmployee(pte2);

        //Department dep = new FADepartment();
        Department dep = new HRDepartment();
        list.accept(dep);
    }
}
⚠️ **GitHub.com Fallback** ⚠️