23种设计模式的详细概念和具体的Java实现【下】

策略模式 Strategy Pattern

策略模式为同一个行为定义了不同策略,为每种策略实现了不同方法。用户使用时系统根据不同的策略自动切换不同的方法实现策略的改变。同一策略下的不同方法是对同一功能的不同实现,因此在使用时可相互替换而不影响用户的使用。

策略模式的实现是在接口中定义不同的策略,在实现类中完成了对不同策略下具体行为的实现,并将用户的策略状态存储在上下文中来完成策略的存储和状态的改变。

以交友的选择为例实现策略模式,具体定义如下:
(1)定义交友策略接口

public interface MakeFriendStrategy {
    
    void makeFriendModel();
}

(2)定义该接口的两种实现方式

public class MakeFriendByWx implements MakeFriendStrategy {
    @Override
    public void makeFriendModel() {
        System.out.println("使用微信交友");
    }
}

public class MakeFriendByQq implements MakeFriendStrategy {
    @Override
    public void makeFriendModel() {
        System.out.println("使用qq交友");
    }
}

(3)定义Context实现策略模式

public class Context {
    
    private MakeFriendStrategy makeFriendStrategy;
    
    public MakeFriendStrategy getMakeFriendStrategy(){
        return makeFriendStrategy;
    }

    public void setMakeFriendStrategy(MakeFriendStrategy makeFriendStrategy) {
        this.makeFriendStrategy = makeFriendStrategy;
    }
    
    public void makeFriendMode(){
        makeFriendStrategy.makeFriendModel();
    }
}

通过set方法实现了不同交友策略的切换

(4)使用策略模式

public static void main(String[] args) {
        Context context = new Context();
        context.setMakeFriendStrategy(new MakeFriendByQq());
        context.makeFriendMode();

        context.setMakeFriendStrategy(new MakeFriendByWx());
        context.makeFriendMode();
    }

在使用策略模式时,需要先定义一个Context,定义不同的策略实现并注入Context实现不同策略的切换,具体执行结果如下:
在这里插入图片描述


模板方法模式 Template Pattern

模板方法模式定义了一个算法框架,并通过继承的方式将算法的实现延迟到子类中,使得子类可以在不改变算法框架及其流程的前提下重新定义该算法在某些特定环节的实现,是一种类行为型模式。

该模式在抽象类中定义了算法的结构并实现了公共部分算法,在子类中实现可变的部分并根据不同的业务需求实现不同的扩展。模板方法模式的优点在于其父类(抽象类)中定义了算法的框架以及保障算法的稳定性,同时在父类中实现了算法公共部分的方法保证代码的复用,将部分算法延迟到子类实现,因此子类可以通过继承扩展或重新定义算法的功能而不影响稳定性,符合开闭原则。

抽象类:定义算法框架,由基本方法和模板方法组成。基本方法定义了算法有哪些环节,模板方法定义了算法各个环节执行的流程。
具体子类:对在抽象类中定义的算法根据需求进行不同的实现。

以银行办理业务为例,具体代码如下:
(1)定义模板类

public abstract class AbstractTemplate {

    void templateMethod(){
        checkNumber();
        queueUp();
        handleBusiness();
        service();

    }

    private void checkNumber(){
        System.out.println("抽号");
    };

    private void queueUp(){
        System.out.println("排队");
    };

    public abstract void handleBusiness();

    private void service(){
        System.out.println("完成服务");
    };
}

(2)实现类

public class SaveMoney extends AbstractTemplate {
    @Override
    public void handleBusiness() {
        System.out.println("存钱");
    }
}

public class TakeMoney extends AbstractTemplate {
    @Override
    public void handleBusiness() {
        System.out.println("取钱");
    }
}

(3)使用模板模式

public static void main(String[] args) {
        AbstractTemplate template1=new SaveMoney();
        template1.templateMethod();
        AbstractTemplate template2=new TakeMoney();
        template2.templateMethod();
    }

具体运行结果如下:
在这里插入图片描述


观察者模式 Observer Pattern

观察者模式指在被观察者的状态发生变化时,系统基于事件驱动理论将其状态通知到订阅其状态的观察者对象中,以完成状态的修改和事件传播。观察者模式是一种对象行为模式,观察者和被观察者之间的关系属于抽象耦合关系,主要优点是观察者与被观察者之间建立了一套事件触发机制,以降低二者之间的耦合度。

观察者模式的主要角色如下:
抽象主题Subject:持有订阅了该主题的观察者对象的集合,同时提供了增加删除观察者对象的方法和主题状态变化后的通知方法
具体主题Concrete Subject:实现了抽象主题的通知方法,在主题内部状态发生变化时,调用该方法通知订阅了主题状态的观察者对象
抽象观察者Observer:观察者的抽象类或接口,定义了主题状态变化时需要调用的方法
具体观察者 Concrete Observer:抽象观察者的实现类,在收到主题状态变化的信息后执行具体触发机制

(1)定义抽象主题Subject

public abstract class Subject {
    protected List<Observer> observers=new ArrayList<>();

    public void add(Observer observer){
        observers.add(observer);
    }

    public void remove(Observer observer){
        observers.remove(observer);
    }

    public abstract void notify(String message);
}

(2)定义具体主题ConcreteSubject

public class ConcreteSubject extends Subject {
    @Override
    public void notify(String message) {
        for(Object obj:observers){
            System.out.println("通知观察者 "+message);
            ((Observer)obj).dataChange(message);
        }
    }
}

(3)定义抽象观察者

public interface Observer {
    
    void dataChange(String message);
}

(4)定义具体的观察者

public class ConcreteObserver implements Observer {


    @Override
    public void dataChange(String message) {
        System.out.println("收到信息 "+message);
    }
}

(5)使用观察者模式

public static void main(String[] args) {
        Subject subject=new ConcreteSubject();
        Observer obs=new ConcreteObserver();
        subject.add(obs);
        subject.notify("lakers win");
    }

运行结果如下:
在这里插入图片描述


迭代器模式 Iterator Pattern

迭代器模式提供了顺序访问集合对象中的各种元素,而不暴露该对象内部结构的方法。Java中的集合就是典型的迭代器模式,比如HashMap,当遍历HashMap时,需要迭代器不停地获取Next元素就可以循环遍历集合中所有元素。

迭代器模式将遍历集合中所有元素地操作封装成一个迭代器类,目的是在不暴露集合对象内部结构地情况下,对外提供统一访问集合内部数据的方法。迭代器的实现一般包括一个迭代器,用于执行具体的遍历操作,以及一个Collection,用于存储具体的数据。以Collection集合的迭代器设计为例,具体代码如下:
(1)定义MyCollection集合接口:

public interface MyCollection {
    //对集合元素的迭代
    Iterator iterator();
    //取得元素
    Object get(int i);
    //添加元素
    boolean add(Object object);
    //集合大小
    int size();
}

(2)定义该接口的实现类MyList:

public class MyList implements MyCollection {
    private List list=new ArrayList();
    
    @Override
    public MyIterator iterator() {
        return new ConcreteIterator(this);
    }}

    @Override
    public Object get(int i) {
        return list.get(i);
    }

    @Override
    public boolean add(Object object) {
        list.add(object);
        return true;
    }

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

(3)定义迭代器接口MyIterator:

public interface MyIterator {
    //指针前移
    Object previous();
    //指针后移
    Object next();
    
    boolean hasNext();
}

(4)迭代器接口实现类ConcreteIterator

public class ConcreteIterator implements MyIterator {
    
    private MyCollection myCollection;
    
    private int pos=-1;
    
    public ConcreteIterator(MyCollection myCollection) {
        this.myCollection=myCollection;
    }
    
    @Override
    public Object previous(){
        if(pos>0)
            pos--;
        return myCollection.get(pos);
    }

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

    @Override
    public boolean hasNext() {
        return pos < myCollection.size() - 1;
    }
}

(5)使用迭代器

public static void main(String[] args) {
        MyCollection myCollection=new MyList();
        myCollection.add("data1");
        myCollection.add("data2");
        MyIterator iterator = myCollection.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

迭代器的使用方法比较简单:定义一个集合并添加数据,然后获取迭代器通过循环遍历,运行结果如下:
在这里插入图片描述


责任链模式 Chain of Responsibility

责任链模式用于避免请求发送者与多个请求处理者耦合在一起,让所有请求的处理者持有下一个对象的引用,从而将请求串联成一条链,在有请求发生时,可将请求沿着这条链传递,直到遇到该对象的处理器。

该模式下用户只需将请求发送到责任链上即可,无需关心请求的处理细节和传递过程,所以责任链模式优雅地将请求的发送和处理进行了解耦。责任链模式常用于Web模式。

责任链模式包含以下三种角色:

  • Handler接口
    规定责任链上要执行的具体方法
  • AbstractHandler抽象类
    持有Handler实例并通过get/set方法将各个具体的业务Handler串联成一个责任链,客户端上的请求在责任链上执行
  • 业务Handler
    用户根据具体的业务需求实现的业务逻辑

以用户鉴权、业务调用、结果反馈为例:
(1)定义Handler接口

public interface Handler {
    void operate();
}

(2)定义AbstractHandler类

public abstract class AbstractHandler {
    private Handler handler;

    public Handler getHandler() {
        return handler;
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }
}

(3)定义用户授权类AuthHandler

public class AuthHandler extends AbstractHandler implements Handler {
    
    private String name;
    
    public AuthHandler(String name){
        this.name=name;
    }
    
    @Override
    public void operate() {
        System.out.println("用户认证");
        if(getHandler()!=null){
            getHandler().operate();
        }
    }
}

(4)定义业务处理类BusinessHandler

public class BusinessHandler extends AbstractHandler implements Handler {

    private String name;

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

    @Override
    public void operate() {
        System.out.println("业务调用");
        if(getHandler()!=null){
            getHandler().operate();
        }
    }
}

(5)定义请求反馈类

public class ResponseHandler extends AbstractHandler implements Handler {

    private String name;

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

    @Override
    public void operate() {
        System.out.println("请求响应");
        if(getHandler()!=null){
            getHandler().operate();
        }
    }
}

(6)使用责任链模式

public static void main(String[] args) {
        AuthHandler authHandler=new AuthHandler("auth");
        BusinessHandler businessHandler=new BusinessHandler("buss");
        ResponseHandler responseHandler=new ResponseHandler("res");
        authHandler.setHandler(businessHandler);
        businessHandler.setHandler(responseHandler);
        authHandler.operate();
    }

使用责任链模式时,首先需要定义各个责任链的组件,然后将各个组件通过set方法串联起来,然后调用第一个责任链上的方法,具体运行结果如下:
在这里插入图片描述


命令模式 Command

命令模式将请求封装为命令基于事件驱动异步执行,以实现命令的发送者和命令的执行者之间的解耦,提高命令发送执行的效率和灵活度。命令模式主要包含以下角色:

  • 抽象命令类
    执行命令的接口,定义执行命令的抽象方法
  • 具体命令类
    抽象命令类的实现类,持有接收者对象,并在收到命令后调用命令执行者的方法action()实现命令的调用和执行
  • 命令执行者
    命令的具体执行者,定义了命令执行的具体方法action()
  • 命令调用者
    接收客户端的命令并异步执行

(1)定义Command接口

public interface Command {
    public void execute(String command);
}

(2)定义具体命令类ConcreteCommand

public class ConcreteCommand implements Command {
    private Receiver receiver;
    
    public ConcreteCommand(Receiver receiver){
        this.receiver=receiver;
    }
    
    @Override
    public void execute(String command) {
        receiver.action(command);    
    }
}

(3)定义命令的接收者和执行者Receiver

public class Receiver {
    
    public void action(String command){
        System.out.println("接收命令,开始执行"+command);
    }
}

(4)定义命令调用者类Invoker

public class Invoker {

    private Command command;

    public Invoker(Command command){
        this.command=command;
    }

    public void action(String command){
        System.out.println("发送命令");
        this.command.execute(command);
    }
}

(5)使用命令模式

public static void main(String[] args) {
        Command command=new ConcreteCommand(new Receiver());
        Invoker invoker=new Invoker(command);
        invoker.action("exe the command");
    }

使用命令模式时要定义一个命令接收和执行者Receiver,接着定义一个具体的命令实例,并将命令接收者实例设置到命令实例中,然后定义一个命令调用者Invoker实例,将命令实例设置到执行者中,最后调用命令调用者的action方法,发送命令,在命令接收者收到数据后会执行相关命令,这样就完成了命令的调用。执行结果如下:
在这里插入图片描述


备忘录模式 Memento

备忘录模式又叫做快照模式,该模式将当前对象的内部状态保存到备忘录中,以便在需要时能将对象的状态恢复到原先保存的状态。备忘录模式提供了一种保存和恢复状态的机制,常用于快照的记录和状态的存储,在系统发生鼓掌或数据发生不一致时能够方便地将数据恢复到某个历史状态。

备忘录的核心是设计备忘录类及用于管理备忘录的管理者类,主要角色如下:

  • 发起人Originator
    记录当前时刻的内部状态,定义创建备忘录和回复备忘录数据的方法
  • 备忘录Memento
    负责存储对象的内部状态
  • 状态管理者Storage
    对备忘录的历史状态进行存储,定义了保存和获取备忘录状态的功能。注意备忘录只能被保存或恢复,不能进行修改。

(1)定义原始数据Original

public class Original {
    
    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
    
    public Memento createMemento(){//创建备忘录
        return new Memento(value);
    }
    
    public void restoreMemento(Memento memento){//恢复数据
        this.value=memento.getValue();
    }
}

(2)定义备忘录Memento

public class Memento {
    private String value;
    
    public Memento(String value){
        this.value=value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

(3)定义备忘录管理者Storage

public class Storage {
    
    private Memento memento;
    
    public Storage(Memento memento){
        this.memento=memento;
    }

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}

以上代码定义了备忘录管理者,持有备忘录实例,并提供了set/get方法用来设置和获取备忘录数据。
(4)使用备忘录

public static void main(String[] args) {
        //创建原始类
        Original original=new Original("original data");
        //创建备忘录
        Storage storage=new Storage(original.createMemento());
        //修改原始类数据
        System.out.println("原始数据:"+original.getValue());
        original.setValue("new data");
        System.out.println("当前数据 "+original.getValue());
        //恢复数据
        original.restoreMemento(storage.getMemento());
        System.out.println("恢复数据为 "+original.getValue());
    }

备忘录的使用方法比较简单,先定义一个原始数据,然后将数据存到Storage,这时可以修改数据,在我们想把数据恢复时,调用原始类的restoreMemento方法即可。执行结果如下:
在这里插入图片描述


状态模式 State

状态模式指给对象定义不同的状态,并为不同的状态定义不同的行为,在对象的状态发生变换时自动切换状态的行为。状态模式是一种对象行为型模式,它将对象的不同行为封装到不同的状态中,遵循单一职责原则。

具体角色如下:
(1)环境: 也叫做上下文,用于维护对象当前的状态,并在对象状态发生变化时触发对象行为的变化
(2)抽象状态:定义接口,用于定义对象中不同状态对应行为
(3)具体状态:抽象状态的实现类

(1)定义AbstractState

public abstract class AbstractState {
    
    public abstract void action(Context context);
}

(2)定义AbstractState的子类HolidayState

public class HolidayState extends AbstractState {
    @Override
    public void action(Context context) {
        System.out.println("切换到假期状态");
    }
}

(3)定义AbstractState的子类WorkState

public class WorkState extends AbstractState {
    @Override
    public void action(Context context) {
        System.out.println("切换到工作状态");
    }
}

(4)定义Context存储状态和执行不同状态下行为

public class Context {
    
    private AbstractState state;
    
    public Context(AbstractState state){
        this.state=state;
    }

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

    public AbstractState getState() {
        return state;
    }
    
    public void action(){
        state.action(this);
    }
}

(5)使用状态模式

public static void main(String[] args) {
        Context context = new Context(new HolidayState());
        context.action();
        context.setState(new WorkState());
        context.action();
    }

使用状态模式时,只需定义一个上下文Context,并设置Context中的状态,然后调用行为方法即可。
在这里插入图片描述


访问者模式 Visitor

访问者模式指将数据结构和数据的操作分离开来,使其在不改变数据结构的前提下动态添加作用于这些元素的操作。访问者模式通过定义不同的访问者实现对数据的不同操作,因此在需要给数据添加新的操作时只需为其定义一个新的访问者即可。

访问者模式是一种对象行为型模式,主要特点是将数据结构和作用于结构上的操作解耦,使得集合的操作可自由地演化而不影响其数据结构,它适用于数据结构稳定但操作多变的系统中。

主要角色如下:

  • 抽象访问者
    定义了一个访问元素的接口,为每类元素都定义了一个访问操作,该操作中的参数类型对应被访问元素的数据类型
  • 具体访问者
    抽象访问者的实现类,实现了不同访问者访问元素后具体行为
  • 抽象元素
    定义了访问该元素的入口方法,不同访问者类型代表不同访问者
  • 具体元素
    实现抽象元素定义的入口方法,根据访问者的不同类型实现不同逻辑业务

以不同员工访问相同项目为例:
(1)定义抽象接口Vistor

public interface Vistor {
    
    void visit(ProjectElement element);
}

(2)定义Vistor实现类Manager

public class Manager implements Vistor {
    @Override
    public void visit(ProjectElement element) {
        System.out.println("管理员审核项目");
        element.signature("manager",new Date());
    }
}

(3)定义Vistor实现类Ceo

public class Ceo implements Vistor {
    @Override
    public void visit(ProjectElement element) {
        System.out.println("CEO审核项目");
        element.signature("ceo",new Date());
    }
}

(4)定义抽象元素Element

public interface Element {
    void accept(Vistor vistor);
}

(5)定义具体元素ProjectElement

public class ProjectElement implements Element {
    private String name;
    private String vistor;
    private Date date;

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

    @Override
    public void accept(Vistor vistor) {
        vistor.visit(this);
    }
    
    public void signature(String vistor,Date time){
        this.vistor=vistor;
        this.date=time;
    }

    public String getName() {
        return name;
    }

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

    public String getVistor() {
        return vistor;
    }

    public void setVistor(String vistor) {
        this.vistor = vistor;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }
}

(6)使用访问者模式

public static void main(String[] args) {
        Element element=new ProjectElement("java");
        element.accept(new Manager());
        element.accept(new Ceo());
    }

执行结果如下:
在这里插入图片描述


中介者模式 Mediator

中介者模式指对象和对象之间不直接交互,而是通过一个名为中介者的角色来实现,使原有对象之间的关系变得松散,且可以通过定义不同的中介者来改变它们之间的交互。主要包含以下角色:

  • 抽象中介者
    中介者接口,定义了注册同事对象方法和转发同时对象信息的方法
  • 具体中介者
    中介者接口的实现类,定义了一个集合保存同事对象,协调各同事角色之间的交互关系
  • 抽象同事类
    定义同事的接口类,持有中介者对象,并定义同事对象交互的抽象方法,同时实现同事类的公共方法和功能
  • 具体同事类
    抽象同事的实现类,在需要与其他同事对象交互时,通过中介者对象来完成

以租房场景为例:
(1)定义抽象的Colleague类

public abstract class Colleague {

    protected Mediator mediator;

    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    //同事类的操作
    public abstract boolean operation(String message);
}

(2)定义具体的房东类

public class ColleagueLandord extends Colleague {
    @Override
    public boolean operation(String message) {
        System.out.println("房东收到中介的消息:"+message);
        return true;
    }
}

(3)定义具体的租户类

public class ColleagueTenant extends Colleague {
    @Override
    public boolean operation(String message) {
        System.out.println("租客收到中介的消息:"+message);
        return true;
    }
}

(4)定义抽象中介者Mediator

public abstract class Mediator {
    protected Colleague colleagueTenant;
    protected Colleague colleagueLandord;

    public Mediator(Colleague colleagueTenant, Colleague colleagueLandord) {
        this.colleagueTenant = colleagueTenant;
        this.colleagueLandord = colleagueLandord;
    }
    
    //通知租客
    public abstract boolean notifyTenant(String message);
    
    //通知房东
    public abstract boolean notifyLandlord(String message);
}

(5)定义具体的中介

public class ConcreteMediator extends Mediator {
    
    public ConcreteMediator(Colleague colleagueTenant, Colleague colleagueLandord) {
        super(colleagueTenant, colleagueLandord);
    }

    @Override
    public boolean notifyTenant(String message) {
        if(colleagueTenant!=null)
            return colleagueTenant.operation(message);
        return false;
    }

    @Override
    public boolean notifyLandlord(String message) {
        if(colleagueLandord!=null)
            return colleagueLandord.operation(message);
        return false;
    }
}

(6)使用中介者模式

public static void main(String[] args) {
        //定义房客类
        Colleague tenant=new ColleagueTenant();
        //定义房东类
        Colleague landlord=new ColleagueLandord();
        //创建中介
        Mediator mediator=new ConcreteMediator(tenant,landlord);
        boolean result=mediator.notifyTenant("想租房吗?");
        if(result)
            mediator.notifyLandlord("想");
        else 
            mediator.notifyLandlord("不想");
    }

使用中介模式时,首先要定义同事类,然后定义中介者并通过中介者完成对象之间的交互。以上代码首先定义了房客和房东类,然后定义了中介者,最后通过中介者的notify方法完成房客和中介者的交互。以上代码流程是中介者首先向房客询问租房需求,然后反馈给房东,运行结果如下:
在这里插入图片描述


解释器模式 Interpreter

解释器模式给定一种语言,并定义该语言的语法表示,然后设计一个解释器来解释语言的语法,这种模式常被用于SQL解析、符号处理引擎等。
解释器模式包含以下主要角色:

  • 抽象表达式
    定义解释器的接口,约定解释器所包含的操作
  • 终结符表达式
    抽象表达式的子类,用来定义语法中和终结符有关的操作,语法中的每一个终结符都应有一个与之对应的终结表达式
  • 非终结符表达式
    抽象表达式的子类,用来定义语法中和非终结符有关的操作,语法中的每条规则都有一个非终结符表达式与之对应
  • 环境
    定义各个解释器需要的共享数据或公共功能

具体实现如下:
(1)定义表达式接口

public interface Expression {
    //解释方法
    void interpret(Context context);
}

(2)定义非终结符表达式

public class NonterminalExpression implements Expression {
    
    private Expression left;
    private Expression right;

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

    @Override
    public void interpret(Context context) {
        //递归调用每一个组成部分的interpret
    }
}

(3)定义终结符表达式

public class TerminalExpression implements Expression {
    
    @Override
    public void interpret(Context context) {
        //终结符表达式的解释操作
    }
}

(4)定义Context

public class Context {

    private HashMap map=new HashMap();

    public void assign(String key,String val){
        //在环境类设值
    }
    
    public String get(String key){
        //获取存储在环境类的值
        return "";
    }
}

发布了66 篇原创文章 · 获赞 302 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_41112238/article/details/104752524