设计模式之行为型模式

模板方法模式

//Hamburg
package com.std.www.designPattern.templateMethod;

public abstract class Hamburg {
    public final void make(){
        System.out.println("===============汉堡制作===============");
        addBread();
        addSauce();
        addOnions();
        addTomato();
        addLettuce();
        addPatty();
        addBread();


    }
    private void addBread(){
        System.out.println("添加面包片");
    }
    private void addLettuce(){
        System.out.println("添加生菜");
    }
    private void addOnions(){
        System.out.println("添加洋葱");
    }
    private void addTomato(){
        System.out.println("添加西红柿");
    }
    public abstract void addPatty();
    private void addSauce(){
        System.out.println("添加美乃滋");
    }
}

//BeefHamburg
package com.std.www.designPattern.templateMethod;

public class BeefHamburg extends Hamburg{

    @Override
    public void addPatty() {
        System.out.println("添加牛肉肉饼");
    }
}
//ChickenHamburg
package com.std.www.designPattern.templateMethod;

public class ChickenHamburg extends Hamburg{

    @Override
    public void addPatty() {
        System.out.println("添加鸡肉肉饼");
    }
}

//Client

package com.std.www.designPattern.templateMethod;

public class Client {
    public static void main(String[] args) {
        Hamburg hamburg=null;
        hamburg=new BeefHamburg();
        hamburg.make();
        hamburg=new ChickenHamburg();
        hamburg.make();
    }
}

模板方法模式一般包含一个抽象类,里面有抽象方法和一般方法,我们这里把算法确定不变的部分在抽象类里面一次性实现并调用,把不确定的部分定义为抽象方法然后交给子类实现,这样就相当于创建了一个方法的模板,里面某些步骤交给子类实现,上面例子中制作一个汉堡其余步骤都是确定的,但是添加的肉饼不确定,根据子类的具体实现来生成不同的汉堡,注意模板方法最好加上final实现,防止模板被重写,模板整体不变,细节改变,适用于一系列步骤中只有少数步骤不同的情况

不足之处对于每一个实现就要有一个子类,这样类的个数会过多

主要角色:

  1. 抽象类(Abstract Class): 定义算法的框架和基本方法,其中的某些步骤由子类延迟实现。

  2. 具体类(Concrete Class): 实现抽象类中定义的延迟实现的步骤,完成算法中的具体细节。

特点:

  • 定义一个算法的骨架,将某些步骤延迟到子类中实现。

  • 子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。

  • 通过模板方法模式,避免了代码重复,将公共部分抽象到父类中。

优点:

  • 提高了代码的复用性,将共同部分提取到父类中。

  • 子类可以灵活地实现特定步骤,符合开闭原则。

  • 便于维护,修改父类的模板方法影响整个算法结构,符合单一职责原则。

缺点:

  • 引入了抽象类和子类,增加了系统的复杂性。

  • 父类的模板方法可能限制了某些特定步骤的实现方式,不够灵活。

适用场景:

  • 当多个子类有共同的方法,并且这些方法逻辑相同时,可以将这部分逻辑抽取到父类的模板方法中。

  • 当需要控制子类的扩展,只允许在特定步骤进行操作时,可以使用模板方法模式。

命令模式

//Command
package com.std.www.designPattern.command;

public interface Command {
    void doAction();
    void undoAction();
}


//LightOnCommand
package com.std.www.designPattern.command;

public class LightOnCommand implements Command{
    private Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void doAction() {
        light.on();
    }

    @Override
    public void undoAction() {
        light.off();
    }
}

//LightOffCommand
package com.std.www.designPattern.command;

public class LightOffCommand implements Command{
    private Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    public void doAction() {
        light.off();
    }

    @Override
    public void undoAction() {
        light.on();
    }
}

//TVOnCommand
package com.std.www.designPattern.command;

public class TVOnCommand implements Command{
    private TV tv;

    public TVOnCommand(TV tv) {
        this.tv = tv;
    }

    @Override
    public void doAction() {
        tv.on();
    }

    @Override
    public void undoAction() {
        tv.off();
    }
}

//TVOffCommand
package com.std.www.designPattern.command;

public class TVOffCommand implements Command{
    private TV tv;

    public TVOffCommand(TV tv) {
        this.tv = tv;
    }

    @Override
    public void doAction() {
        tv.off();
    }

    @Override
    public void undoAction() {
        tv.on();
    }
}

//Light
package com.std.www.designPattern.command;

public class Light {
    public void on(){
        System.out.println("打开电灯");
    }
    public void off(){
        System.out.println("关闭电灯");
    }
}

//TV
package com.std.www.designPattern.command;

public class TV {
    public void on(){
        System.out.println("打开电视");
    }
    public void off(){
        System.out.println("关闭电视");
    }
}

//Remote
package com.std.www.designPattern.command;

import com.std.www.designPattern.adapter.Adapter;

public class Remote {
    private Command[] commands;
    private Command backCommand;

    public Remote() {
        commands=new Command[4];
        for (Command command : commands) {
            command=new NoCommand();
        }
    }
    public void setCommand(int index,Command command){
        commands[index]=command;
    }
    public void pushButton(int index){
        commands[index].doAction();
        backCommand=commands[index];
    }
    public void backButton(){
        System.out.println("=========撤销最近一次操作=========");
        backCommand.undoAction();
    }
}

//Client
package com.std.www.designPattern.command;

public class Client {
    public static void main(String[] args) {
        Light light=new Light();
        TV tv=new TV();
        Command lightOn=new LightOnCommand(light);
        Command lightOff=new LightOffCommand(light);
        Command TVOn=new TVOnCommand(tv);
        Command TVOff=new TVOffCommand(tv);
        Remote remote=new Remote();
        remote.setCommand(0,lightOn);
        remote.setCommand(1,lightOff);
        remote.setCommand(2,TVOn);
        remote.setCommand(3,TVOff);
        remote.pushButton(0);
        remote.pushButton(1);
        remote.pushButton(2);
        remote.pushButton(3);
        remote.backButton();
    }
}

命令模式实例化了请求为对象,将发送者和接受者解耦

一般包含一个Invoker,聚合了一系列的命令,一个命令接口,包含执行和撤销两个操作,多个接收者,对于每个具体的命令类,由对应的接受者来执行相关的操作,原本是Invoker直接发送命令给每个Receiver,现在发送方只负责实例化命令,至于是哪个接受者接受的则无需关心。例如上面例子中Remote为Invoker,对于每个按钮命令发送出去为谁执行无需关心,一般会增加一个NoCommand类用来表示初始状态,同时支持撤销命令操作.。

缺点就是命令类过多

主要角色:

  1. 命令接口(Command): 声明执行操作的接口。

  2. 具体命令(ConcreteCommand): 实现了命令接口,定义了如何执行具体的命令。

  3. 调用者(Invoker): 要求命令执行请求的对象。

  4. 接收者(Receiver): 知道如何执行与请求相关的操作。任何类都可能成为一个接收者。

  5. 客户端(Client): 创建一个具体的命令对象并设置它的接收者。

特点:

  • 将请求发送者和接收者解耦。

  • 可以将多个命令组合成复合命令。

  • 可以支持命令的撤销(Undo)和恢复(Redo)。

优点:

  • 降低系统的耦合度。

  • 新的命令可以很容易地加入系统。

  • 可以实现命令的排队和记录。

  • 支持可撤销的操作。

缺点:

  • 可能导致大量的具体命令类的创建。

适用场景:

  • 需要将请求发送者和接收者解耦。

  • 需要在不同的时间指定请求、将请求排队、记录请求以及支持撤销操作。

  • 系统支持命令的撤销和恢复。

  • 用于实现宏命令。

访问者模式

//Person
package com.std.www.designPattern.visitor;

public interface Person {
    void goSummerhouse(Summerhouse summerhouse);
    void goTemple(Temple temple);

}
//Tourist
package com.std.www.designPattern.visitor;

public class Tourist implements Person{
    @Override
    public void goSummerhouse(Summerhouse summerhouse) {
        System.out.println("游客参观凉亭");
    }

    @Override
    public void goTemple(Temple temple) {
        System.out.println("游客参观庙宇");
    }
}

//Janitor
package com.std.www.designPattern.visitor;

public class Janitor implements Person{
    @Override
    public void goSummerhouse(Summerhouse summerhouse) {
        System.out.println("清洁工打扫凉亭");
    }

    @Override
    public void goTemple(Temple temple) {
        System.out.println("清洁工打扫庙宇");
    }
}

//Attraction
package com.std.www.designPattern.visitor;

public interface Attraction {
    void accept(Person person);

}

//Summerhouse
package com.std.www.designPattern.visitor;

public class Summerhouse implements Attraction{
    @Override
    public void accept(Person person) {
        person.goSummerhouse(this);
    }
}

//Temple
package com.std.www.designPattern.visitor;

public class Temple implements Attraction{
    @Override
    public void accept(Person person) {
        person.goTemple(this);
    }
}

//ObjectStructure
package com.std.www.designPattern.visitor;

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

public class ObjectStructure {
    private List<Attraction> attractions=new ArrayList<>();
    public void addAttraction(Attraction attraction){
        attractions.add(attraction);
    }
    public void removeAttraction(Attraction attraction){
        attractions.remove(attraction);
    }
    public void displayAttraction(Person person){
        for (Attraction attraction : attractions) {
            attraction.accept(person);
        }
    }
}

//Client
package com.std.www.designPattern.visitor;

public class Client {
    public static void main(String[] args) {
        ObjectStructure objectStructure=new ObjectStructure();
        objectStructure.addAttraction(new Summerhouse());
        objectStructure.addAttraction(new Temple());
        objectStructure.displayAttraction(new Tourist());
        objectStructure.displayAttraction(new Janitor());

    }
}

访问者模式三个主要的类,Visitor,Element和ObjectStructure,每个Element都有一个accept操作用于接受访问者,而ObjectStructure为Element的数据结构让高层得以访问各个元素,这里最重要的就是双分派模式,使得增加一个Visitor子类直接调用即可,无需改动任何代码,上面的Person为Visitor,Attraction为Element

访问者模式的优点

主要角色:

  1. 抽象访问者(Visitor): 定义了访问元素的接口,为每个具体元素类型都声明一个访问操作方法。

  2. 具体访问者(ConcreteVisitor): 实现了抽象访问者定义的接口,提供具体的访问行为。

  3. 抽象元素(Element): 声明了一个接受访问者的方法,通常是accept(Visitor visitor)

  4. 具体元素(ConcreteElement): 实现了抽象元素的接口,通常包含一个接受访问者的方法,将自己传入访问者。

  5. 对象结构(Object Structure): 它是一个元素的集合,提供一个接口让访问者可以遍历元素。

特点:

  • 将数据结构与数据操作分离,使得新增访问者类变得相对容易。

  • 增加新的访问者无需修改现有元素的代码。

优点:

  • 增加新的访问者类变得相对容易。

  • 符合开闭原则,能够在不修改元素类的情况下增加新的操作。

缺点:

  • 增加新的元素类比较困难,因为所有的访问者类都需要相应修改。

适用场景:

  • 当一个对象结构包含很多具体类对象,且这些对象有不同的操作时,使用访问者模式可以将操作集中管理。

  • 当对象结构中的元素类的数目比较稳定,但经常需要在此结构上定义新的操作时,使用访问者模式比较适合。

  • 当对象结构中的每个元素类的操作不一样,而且经常需要在此结构上增加新的操作时,使用访问者模式比较适合。

职责链模式

//SchoolPerson
package com.std.www.designPattern.chainofResponsibility;

public abstract class SchoolPerson {
    protected SchoolPerson schoolPerson;
    protected String name;

    public SchoolPerson(String name) {
        this.name=name;
    }
    public void setSchoolPerson(SchoolPerson schoolPerson){
        this.schoolPerson=schoolPerson;
    }
    public abstract void solveTask(String task);
}

//Student
package com.std.www.designPattern.chainofResponsibility;

public class Student extends SchoolPerson{


    public Student(String name) {
        super(name);
    }

    @Override
    public void solveTask(String task) {
        if (task.equals("学生")){
            System.out.println("学生处理任务请求");
        }
        else {
            System.out.println("学生权限不够处理任务请求");
            this.setSchoolPerson(new Teacher("老师"));
            schoolPerson.solveTask(task);
        }
    }
}

//Teacher
package com.std.www.designPattern.chainofResponsibility;

public class Teacher extends SchoolPerson{
    public Teacher(String name) {
        super(name);
    }

    @Override
    public void solveTask(String task) {
        if (task.equals("老师")){
            System.out.println("老师处理任务请求");
        }
        else {
            System.out.println("老师权限不够处理任务请求");
            this.setSchoolPerson(new Director("主任"));
            schoolPerson.solveTask(task);
        }
    }
}

//Director
package com.std.www.designPattern.chainofResponsibility;

public class Director extends SchoolPerson{

    public Director(String name) {
        super(name);
    }


    @Override
    public void solveTask(String task) {
        if (task.equals("主任")){
            System.out.println("主任处理任务请求");
        }
        else {
            System.out.println("主任权限不够处理任务请求");
            this.setSchoolPerson(new Headmaster("校长"));
            schoolPerson.solveTask(task);
        }
    }
}

//Headmaster
package com.std.www.designPattern.chainofResponsibility;

public class Headmaster extends SchoolPerson {

    public Headmaster(String name) {
        super(name);
    }


    @Override
    public void solveTask(String task) {
        if (task.equals("校长")){
            System.out.println("校长处理任务请求");
        }
        else {
            System.out.println("学校无人有权限执行该任务请求");
        }
    }
}

//Client
package com.std.www.designPattern.chainofResponsibility;

public class Client {
    public static void main(String[] args) {
        new Student("学生").solveTask("主任");
        new Student("学生").solveTask("校长");
        new Student("学生").solveTask("县长");
    }
}

职责链模式包含一个Handler抽象类,里面有主要有两个方法一个是设置请求传递的下一个的类的方法和一个当前类对请求的处理方法 ,适用于多个对象处理同一个请求的情况,该请求会一直传递直到被解决或者无对象可以解决才会停止传递

主要角色:

  1. 处理者(Handler): 定义了一个处理请求的接口,通常包含一个指向下一个处理者的引用。

  2. 具体处理者(ConcreteHandler): 实现了处理请求的具体逻辑,如果能够处理请求,则处理之;否则,将请求传递给下一个处理者。

  3. 客户端(Client): 创建处理者链并将请求发送给链的第一个处理者。

特点:

  • 请求发送者无需知道是哪个对象处理请求,处理者对象也无需知道请求的发送者或者是哪个处理者处理的请求。

  • 每个处理者都只关心自己处理的请求,不关心其他请求和处理者。

优点:

  • 将请求的发送者和接收者解耦,使得更容易扩展和修改处理链。

  • 可以灵活地调整链中处理者的顺序。

  • 可以动态地添加或删除处理者。

缺点:

  • 请求可能到达链的末尾而得不到处理,或者因为链配置不当,请求不能够被正常处理。

  • 处理者链过长或者处理者链设计不当可能会导致性能问题。

适用场景:

  • 有多个对象可以处理一个请求,但是具体哪个对象处理请求在运行时确定。

  • 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。

  • 需要动态指定可以处理请求的对象集合。

状态模式

//State
package com.std.www.designPattern.state;

public abstract class State {
    protected Context context;

    public State(Context context) {
        this.context = context;
    }

    public abstract void deductMoney();
    public abstract boolean raffle();
    public abstract void  dispensePrize();
}

NoRaffleState

package com.std.www.designPattern.state;

public class NoRaffleState extends State{

    public NoRaffleState(Context context) {
        super(context);
    }

    @Override
    public void deductMoney() {
        System.out.println("扣除积分,获取抽奖资格");
        context.setState(new CanRaffleState(context));

    }

    @Override
    public boolean raffle() {
        System.out.println("请先获取抽奖资格");
        return false;
    }

    @Override
    public void dispensePrize() {
        System.out.println("请先获取抽奖资格");
    }
}

CanRaffleState

package com.std.www.designPattern.state;

import java.util.Random;

public class CanRaffleState extends State{
    public CanRaffleState(Context context) {
        super(context);
    }

    @Override
    public void deductMoney() {
        System.out.println("已获取抽奖资格");
    }

    @Override
    public boolean raffle() {
        System.out.println("开始抽奖");
        Random random=new Random();
        if(random.nextInt(3)==0){
            System.out.println("恭喜你中奖了");
            context.setState(new DispenseState(context));
            return true;

        }else {
            System.out.println("很遗憾,未中奖,抽奖资格已耗光");
            context.setState(new NoRaffleState(context));
            return false;
        }
    }

    @Override
    public void dispensePrize() {
        System.out.println("请先抽奖");
    }
}

DispenseState

package com.std.www.designPattern.state;

public class DispenseState extends State{
    public DispenseState(Context context) {
        super(context);
    }

    @Override
    public void deductMoney() {
        System.out.println("请先领取奖品");
    }

    @Override
    public boolean raffle() {
        System.out.println("请先领取奖品");
        return false;
    }

    @Override
    public void dispensePrize() {
        if(context.getPrize()>0){
            context.givePrize();
            System.out.println("奖品已经发放");
            context.setState(new NoRaffleState(context));
        }
        else {
            System.out.println("奖品发放完毕,活动结束");
            context.setState(new DispenseOutState(context));
        }
    }
}

DispenseOutState

package com.std.www.designPattern.state;

public class DispenseOutState extends State{
    public DispenseOutState(Context context) {
        super(context);
    }

    @Override
    public void deductMoney() {
        System.out.println("奖品发放完毕,活动结束");
    }

    @Override
    public boolean raffle() {
        System.out.println("奖品发放完毕,活动结束");
        return false;
    }

    @Override
    public void dispensePrize() {
        System.out.println("奖品发放完毕,活动结束");
    }
}

Context

package com.std.www.designPattern.state;

public class Context{
    private int prize=1;
    private State state;


    public void setState(State state) {
        this.state = state;
    }

    public int getPrize() {
        return prize;
    }
    public void givePrize(){
        prize--;
    }

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

    public boolean raffle() {
        return state.raffle();
    }

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

Client

package com.std.www.designPattern.state;

public class Client {
    public static void main(String[] args) {
        Context context=new Context();
        context.setState(new NoRaffleState(context));
        for (int i=0;i<5;i++){
            System.out.println("======== 第"+String.valueOf(i)+"次 ========");
            context.deductMoney();
            context.raffle();
            context.dispensePrize();
        }
    }
}

状态模式一般包含一个抽象状态类,一个上下文环境类,抽象状态类定义了各种方法,在不同的状态下,相同的方法执行不同的动作,上下文环境聚集了各种状态,根据状态的变化,上下文环境执行不同的动作,上面的例子为一个抽奖系统,分为四个状态,不能抽奖,可抽奖,可领奖,活动结束,三个方法获取资格,抽奖和领奖,这体现了多态性

主要角色:

  1. 环境(Context): 定义客户端感兴趣的接口,并且维护一个具体状态角色的实例,这个实例定义当前状态。

  2. 抽象状态(State): 定义一个接口,用于封装环境中的一个特定状态的行为。

  3. 具体状态(Concrete State): 实现抽象状态定义的接口,即具体的状态类。

特点:

  • 状态切换: 对象在不同的状态下有不同的行为,可以在运行时切换状态。

  • 封装性: 将状态的行为封装在不同的状态类中,使得每个状态类的代码相对独立。

  • 减少条件判断: 避免使用过多的 if-else 语句,将状态判断分散到各个状态类中。

优点:

  • 可维护性: 将状态的转换规则封装在具体状态类中,易于新增、删除或修改状态,不会影响其他状态的代码。

  • 可扩展性: 可以方便地引入新的状态类,扩展系统的行为。

缺点:

  • 增加类的个数: 引入了多个状态类,增加了系统的类的个数和复杂度。

适用场景:

  • 当对象的行为取决于它的状态,并且在运行时可以根据状态改变而改变行为时。

  • 当一个操作中含有庞大的多分支的条件语句,且这些分支依赖于对象的状态时,可以考虑使用状态模式。

策略模式

//PaymentStrategy
package com.std.www.designPattern.strage;

public interface PaymentStrategy {
    void pay(int amount);
}
//CreditCardPayment

package com.std.www.designPattern.strage;

public class CreditCardPayment implements PaymentStrategy{
    private String cardNumber;

    public CreditCardPayment(String cardNumber) {
        this.cardNumber = cardNumber;
    }

    @Override
    public void pay(int amount) {
        System.out.println("信用卡卡号为:"+cardNumber+"\t付款:"+amount);
    }
}


//WeChatPayment

package com.std.www.designPattern.strage;

public class WeChatPayment implements PaymentStrategy{
    private String userName;

    public WeChatPayment(String userName) {
        this.userName = userName;
    }

    @Override
    public void pay(int amount) {
        System.out.println("微信用户名为:"+userName+"\t付款:"+amount);
    }
}


//AlipayPayment

package com.std.www.designPattern.strage;

public class AlipayPayment implements PaymentStrategy{
    private String account;

    public AlipayPayment(String account) {
        this.account = account;
    }

    @Override
    public void pay(int amount) {
        System.out.println("支付宝账号为:"+account+"\t付款:"+amount);
    }
}


//Context

package com.std.www.designPattern.strage;

public class Context {
    private PaymentStrategy paymentStrategy;

    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void checkout(int amount) {
        paymentStrategy.pay(amount);
    }
}


//Client 

package com.std.www.designPattern.strage;

public class Client {
    public static void main(String[] args) {
        Context context=new Context();
        context.setPaymentStrategy(new WeChatPayment("小王"));
        context.checkout(100);
        context.setPaymentStrategy(new AlipayPayment("支付宝花呗"));
        context.checkout(50);
        context.setPaymentStrategy(new CreditCardPayment("111111255"));
        context.checkout(30);
    }
}
策略模式和状态模式相似,都有一个环境上下文,上面根据不同的支付方式进行付款,状态模式和策略模式都是通过将if else分解为多个模块,使用set注入来选中相对的模块

主要角色:

  1. 环境(Context): 持有一个策略类的引用,负责调用具体的策略类。通常接受客户的请求,并将请求委派给策略对象。

  2. 抽象策略(Strategy): 定义了一个策略家族的接口,所有具体策略类都实现这个接口。

  3. 具体策略(Concrete Strategy): 实现了抽象策略接口,提供具体的算法实现。

特点:

  • 封装变化: 将算法封装在独立的策略类中,使得可以独立于客户端变化。

  • 替换规则: 允许客户在不修改算法的情况下更改算法。

  • 减少条件语句: 避免使用多重条件语句。

优点:

  • 灵活性: 可以动态地切换算法,满足不同的需求。

  • 可维护性: 将每个算法封装到具体的策略类中,易于理解和修改。

  • 可扩展性: 客户端可以自行增加新的策略。

缺点:

  • 客户端需要了解所有的策略类,选择合适的策略。

适用场景:

  • 当一个系统需要有多种算法,可动态切换时。

  • 当一个对象有很多行为,而客户端需要动态地选择其中一种时。

  • 当类定义中有多种行为,而且这些行为在将来可能会发生变化时,可以考虑使用策略模式。

 

解释器模式

package com.std.www.designPattern.Interpre;

// 抽象表达式
interface Expression {
    int interpret();
}

// 终结符表达式
class NumberExpression implements Expression {
    private int number;

    public NumberExpression(int number) {
        this.number = number;
    }

    @Override
    public int interpret() {
        return number;
    }
}

// 非终结符表达式 - 加法
class AddExpression implements Expression {
    private Expression left;
    private Expression right;

    public AddExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret() {
        return left.interpret() + right.interpret();
    }
}

// 非终结符表达式 - 乘法
class MultiplyExpression implements Expression {
    private Expression left;
    private Expression right;

    public MultiplyExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret() {
        return left.interpret() * right.interpret();
    }
}

// 环境
class Context {
    private String expression;

    public Context(String expression) {
        this.expression = expression;
    }

    public int evaluate() {
        // 解析表达式并构建解释树
        Expression syntaxTree = parseExpression(expression);
        // 计算表达式的值
        return syntaxTree.interpret();
    }

    private Expression parseExpression(String expression) {
        // 实现解析表达式的逻辑,这里简化为示例
        // 实际应用中可能需要使用词法分析器、语法分析器等工具
        // 此处直接构建一个简单的解释树
        return new AddExpression(
                new NumberExpression(1),
                new MultiplyExpression(
                        new NumberExpression(2),
                        new NumberExpression(3)
                )
        );
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        String expression = "1 + 2 * 3";
        Context context = new Context(expression);
        int result = context.evaluate();
        System.out.println(expression + " = " + result);
    }
}

在这个示例中,Expression 定义了解释操作的接口,NumberExpressionAddExpressionMultiplyExpression 是具体的表达式实现。 Context 类包含要解释的表达式,并负责解析和计算。

主要角色:

  1. 抽象表达式(Abstract Expression): 声明一个抽象的解释操作,这个接口为所有的具体表达式定义了解释操作的方法。

  2. 终结符表达式(Terminal Expression): 实现了抽象表达式的接口,是文法中的终结符对应的表达式。

  3. 非终结符表达式(Non-terminal Expression): 实现了抽象表达式的接口,是文法中的非终结符对应的表达式。它通常是由多个终结符或非终结符组成。

  4. 环境(Context): 包含解释器之外的一些全局信息,它通常负责对输入表达式进行分析和解释。

特点:

  • 规定了文法的语法表示,用于解释一个特定的语言。

  • 每个终结符表达式和非终结符表达式都有一个解释操作。

  • 通过组合表达式来构建解释树,实现对表达式的解释。

优点:

  • 灵活性: 可以动态地修改或扩展文法。

  • 易于实现文法: 易于添加新的表达式。

缺点:

  • 复杂度: 当文法规则较为复杂或者文法变化频繁时,维护解释器的类结构和规则可能变得很复杂。

适用场景:

  • 当有一个语言需要解释执行,并且可以将该语言中的语句表示为一个抽象语法树时。

  • 当文法规则相对固定,但经常需要扩展时。

迭代器模式

package com.std.www.designPattern.Iterator;
// 抽象迭代器
interface Iterator<T> {
    boolean hasNext();

    T next();
}

// 具体迭代器
class ConcreteIterator<T> implements Iterator<T> {
    private final T[] elements;
    private int currentIndex = 0;

    public ConcreteIterator(T[] elements) {
        this.elements = elements;
    }

    @Override
    public boolean hasNext() {
        return currentIndex < elements.length;
    }

    @Override
    public T next() {
        if (hasNext()) {
            return elements[currentIndex++];
        }
        throw new IllegalStateException("没有元素");
    }
}

// 抽象聚合
interface Aggregate<T> {
    Iterator<T> createIterator();
}

// 具体聚合
class ConcreteAggregate<T> implements Aggregate<T> {
    private final T[] elements;

    public ConcreteAggregate(T[] elements) {
        this.elements = elements;
    }

    @Override
    public Iterator<T> createIterator() {
        return new ConcreteIterator<>(elements);
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        // 创建一个聚合对象,例如一个数组
        String[] names = {"Alice", "Bob", "Charlie", "David"};

        // 使用具体聚合创建一个迭代器
        Aggregate<String> aggregate = new ConcreteAggregate<>(names);
        Iterator<String> iterator = aggregate.createIterator();

        // 使用迭代器遍历聚合对象
        while (iterator.hasNext()) {
            String name = iterator.next();
            System.out.println("姓名: " + name);
        }
    }
}

  1. 迭代器(Iterator):定义访问和遍历元素的接口,并保持迭代的当前位置。

  2. 具体迭代器(Concrete Iterator):实现迭代器接口,负责管理遍历过程中的当前位置。

  3. 聚合(Aggregate):定义创建相应迭代器对象的接口。

  4. 具体聚合(Concrete Aggregate):实现创建相应迭代器的接口,返回具体迭代器的实例。

特点:

  1. 封装性:客户端无需了解聚合对象的内部结构,通过迭代器访问元素。

  2. 统一访问:提供一致的接口,使得客户端可以使用相同的方式遍历不同类型的聚合对象。

  3. 支持多次遍历:迭代器模式允许多个迭代器同时遍历聚合对象,而不会相互干扰。

优点:

  1. 简化客户端代码:客户端无需知道聚合对象的内部结构,只需通过迭代器访问元素。

  2. 支持多种遍历方式:可以定义不同类型的迭代器,满足不同遍历需求。

  3. 迭代器与聚合对象解耦:客户端与具体聚合对象的实现解耦,可以更灵活地替换聚合对象或迭代器。

缺点:

  1. 增加类的个数:引入了迭代器接口和具体迭代器类,增加了类的数量。

  2. 可能降低性能:在某些情况下,直接访问聚合对象可能更高效,而使用迭代器可能引入额外的开销。

适用场景:

  1. 需要访问聚合对象的元素,但不希望暴露其内部结构。

  2. 需要提供多种遍历方式,而不影响聚合对象的代码。

  3. 希望在不同聚合对象之间实现统一的遍历接口。

中介者模式

//Mediator

package com.std.www.designPattern.mediator;

public abstract class Mediator {
    public abstract void register(String colleagueName,Colleague colleague);
    public abstract void getMessage(int stateChange,String colleague);
}


//ConcreteMediator

package com.std.www.designPattern.mediator;

import java.util.HashMap;
import java.util.Map;

public class ConcreteMediator extends Mediator{
    private Map<String,Colleague> colleagueMap;
    private Map<String,String> interMap;


    public ConcreteMediator() {
        this.colleagueMap = new HashMap<>();
        this.interMap = new HashMap<>();
    }

    @Override
    public void register(String colleagueName, Colleague colleague) {
        colleagueMap.put(colleagueName,colleague);
        switch (colleague.getClass().getSimpleName()){
            case "Alarm":
                interMap.put("Alarm",colleagueName);
                break;
            case "TV":
                interMap.put("TV",colleagueName);
                break;
            case "Light":
                interMap.put("Light",colleagueName);
                break;
            case "Door":
                interMap.put("Door",colleagueName);
                break;
        }

    }

    @Override
    public void getMessage(int stateChange, String colleague) {
        switch (colleagueMap.get(colleague).getClass().getSimpleName()){
            case "Alarm":
                if (stateChange==0){
                    ((Alarm)colleagueMap.get(interMap.get("Alarm"))).startAlarm();
                    ((Light)colleagueMap.get(interMap.get("Light"))).startLight();
                }
                else {
                    ((Alarm)colleagueMap.get(interMap.get("Alarm"))).stopAlarm();
                    ((Light)colleagueMap.get(interMap.get("Light"))).stopLight();
                }
                break;
            case "TV":
                ((TV)colleagueMap.get(interMap.get("TV"))).startTV();
                break;
            case "Light":
                System.out.println("不做处理");
                break;
            case "Door":
                ((Door)colleagueMap.get(interMap.get("Door"))).startDoor();
                ((TV)colleagueMap.get(interMap.get("TV"))).stopTV();
                break;
        }
    }
}


//Alarm


package com.std.www.designPattern.mediator;

public class Alarm extends Colleague {
    public Alarm(Mediator mediator, String name) {
        super(mediator, name);
        mediator.register(name,this);
    }
    public void sendAlarm(int stateChange) {
        sendMessage(stateChange);
    }
    public void startAlarm(){
        System.out.println("发出警报");
    }
    public void stopAlarm(){
        System.out.println("停止警报");
    }

    @Override
    public void sendMessage(int stateChange) {
        this.getMediator().getMessage(stateChange,this.name);
    }
}


//TV

package com.std.www.designPattern.mediator;

public class TV extends Colleague{
    public TV(Mediator mediator, String name) {
        super(mediator, name);
        mediator.register(name,this);
    }

    public void sendTV(int stateChange) {
        sendMessage(stateChange);
    }
    public void startTV(){
        System.out.println("打开电视");
    }
    public void stopTV(){
        System.out.println("关闭电视");
    }

    @Override
    public void sendMessage(int stateChange) {
        this.getMediator().getMessage(stateChange,this.name);
    }
}


//Light


package com.std.www.designPattern.mediator;

public class Light extends Colleague{
    public Light(Mediator mediator, String name) {
        super(mediator, name);
        mediator.register(name,this);
    }

    public void sendLight(int stateChange) {
        sendMessage(stateChange);
    }
    public void startLight(){
        System.out.println("打开警示灯");
    }
    public void stopLight(){
        System.out.println("关闭警示灯");
    }

    @Override
    public void sendMessage(int stateChange) {
        this.getMediator().getMessage(stateChange,this.name);
    }
}


//Door

package com.std.www.designPattern.mediator;

public class Door extends Colleague{
    public Door(Mediator mediator, String name) {
        super(mediator, name);
        mediator.register(name,this);
    }

    public void sendDoor(int stateChange) {
        sendMessage(stateChange);
    }
    public void startDoor(){
        System.out.println("打开门");
    }
    public void stopDoor(){
        System.out.println("关闭门");
    }

    @Override
    public void sendMessage(int stateChange) {
        this.getMediator().getMessage(stateChange,this.name);
    }
}


//Client


package com.std.www.designPattern.mediator;

public class Client {
    public static void main(String[] args) {
        Mediator mediator=new ConcreteMediator();
        Alarm alarm=new Alarm(mediator,"alarm");
        TV tv=new TV(mediator,"tv");
        Light light=new Light(mediator,"light");
        Door door=new Door(mediator,"door");
        alarm.sendAlarm(0);
        alarm.sendAlarm(1);
        tv.sendMessage(0);
        light.sendMessage(0);
        door.sendMessage(0);

    }
}

中介者模式中有个MVC模式,其中就是通过Controller层来完成Model层和View层的交互,上面的例子为一个智能控制中介者,我们这里通过map来注册中介者相关的同事,同事发送消息,中介者接受到会待用对应的操作,中介者的关键为注册和消息接受

主要角色:

  1. 中介者(Mediator): 定义了同事对象之间的通信接口,负责协调各同事对象的交互。

  2. 具体中介者(Concrete Mediator): 实现了中介者接口,负责实际协调同事对象的行为,了解并维护同事对象之间的关系。

  3. 同事(Colleague): 每个同事对象都知道中介者对象,并通过中介者进行通信。

  4. 具体同事(Concrete Colleague): 实现了同事接口,是具体的业务对象。每个具体同事对象都知道中介者对象,并通过中介者进行通信。

特点:

  • 减少直接关联: 通过引入中介者对象,减少了对象之间的直接关联,降低了耦合度。

  • 集中控制: 将对象之间的关系集中到中介者中,使中介者对象成为系统的"控制塔"。

  • 简化交互: 同事对象不再需要了解其他同事对象的具体实现,只需通过中介者进行通信,使交互更加简单。

优点:

  • 降低耦合度: 中介者模式将对象之间的依赖关系集中在中介者对象中,降低了对象之间的直接耦合。

  • 易于扩展: 新增同事对象时,只需要关注同事对象和中介者的交互,无需修改其他同事对象的代码。

  • 简化对象: 同事对象不再需要了解其他同事对象的详细信息,使对象更加简化。

缺点:

  • 中介者复杂性: 随着业务的复杂性增加,中介者对象可能变得过于复杂,负担过重。

  • 集中化: 过度使用中介者模式可能导致系统变得过于集中化,中介者对象成为系统的瓶颈。

适用场景:

  • 当对象之间存在复杂的交互关系,且耦合度较高时,可以考虑使用中介者模式。

  • 当一个对象的行为依赖于其他对象的行为,并且希望避免直接的依赖关系时。

  • 当需要一个集中控制点来协调多个对象之间的交互时,以减少系统的耦合度。

  • 当系统中的对象过多,导致对象之间的关系复杂难以维护时,中介者模式可以帮助简化关系结构。

备忘录模式

// Memento

package com.std.www.designPattern.memento;

public class Memento {
    private String State;

    public Memento(String state) {
        State = state;
    }

    public String getState() {
        return State;
    }

    public void setState(String state) {
        State = state;
    }
}


// Originator

package com.std.www.designPattern.memento;

public class Originator {
    private String state;

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
    public Memento saveStateMemento(){
        return new Memento(state);
    }
    public void getStateFromMemento(Memento memento){
        state=memento.getState();
    }
}


// Caretaker


package com.std.www.designPattern.memento;

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

public class Caretaker {
    private List<Memento> mementos=new ArrayList<>();
    public void addMemento(Memento memento){
        mementos.add(memento);
    }
    public Memento get(int index){
        return mementos.get(index);
    }
}


// Client


package com.std.www.designPattern.memento;

public class Client {
    public static void main(String[] args) {
        Originator originator=new Originator();
        Caretaker caretaker=new Caretaker();
        originator.setState("状态1");
        caretaker.addMemento(originator.saveStateMemento());
        System.out.println("当前状态: "+originator.getState());
        originator.setState("状态2");
        caretaker.addMemento(originator.saveStateMemento());
        System.out.println("当前状态: "+originator.getState());
        originator.setState("状态3");
        caretaker.addMemento(originator.saveStateMemento());
        System.out.println("当前状态: "+originator.getState());
        originator.getStateFromMemento(caretaker.get(0));
        System.out.println("恢复到状态1");
        System.out.println("当前状态: "+originator.getState());
    }
}

主要角色:

  1. Originator(发起人):拥有需要备份的内部状态的对象。它可以创建和恢复备忘录对象,并将其内部状态设置为备忘录的状态。

  2. Memento(备忘录):负责存储 Originator 对象的内部状态。备忘录可以保存或恢复内部状态,但是不能访问它。

  3. Caretaker(负责人):负责保存备忘录,但是不对备忘录的内容进行操作。主要用于管理多个备忘录对象。

特点:

  • 封装性: 备忘录模式通过封装了对象的状态,使得对象的状态变化对其他对象是不可见的。

  • 恢复性: 允许在需要的时候,将对象恢复到之前的状态。

  • 版本管理: 可以存储和管理多个状态的历史记录。

优点:

  • 封装性良好: 将对象状态封装在备忘录中,避免了对象状态的直接暴露。

  • 版本管理: 可以实现对对象状态的版本管理。

缺点:

  • 资源消耗: 如果需要管理大量的状态历史记录,可能会占用较多的资源。

适用场景:

  • 需要保存和还原对象状态的场景。

  • 需要提供撤销和重做功能的场景。

  • 需要实现版本管理的场景。

posted @ 2023-10-31 22:07  突破铁皮  阅读(4)  评论(0编辑  收藏  举报