(四)设计模式——代理,职责链,命令模式

代理模式(proxy)


描述:为其它对象提供一种代理以控制(隔离,使用接口)对这个对象的访问

场景:

在某应用软件中需要记录业务方法的调用日志,在不修改现有业务类的基础上为每一个类提供一个日志记录代理类,在代理类中输出日志,如在业务方法method()调用之前输出“方法method()被调用,调用时间为2018-05-01 10:10:10”,调用之后如果没有抛异常则输出“方法method()调用成功”,否则输出“方法method()调用失败”。在代理类中调用真实业务的业务方法,使用代理模式设计该日志记录模块的结构。

在这里插入图片描述

 
java代码如下:

package org.crudboy;

interface AbstractLog {
    void method();
}

class BusinessClass implements AbstractLog {
    public void method() {
        System.out.println("业务内容");
    }
}

/** 代理类与代理对象实现同一接口 **/
class LoggerProxy implements AbstractLog {
    private BusinessClass business = new BusinessClass();
    public void method() {
        System.out.println("打印日志");
        business.method();
    }
}

public class Proxy {
    public static void main(String[] args) {
        AbstractLog abstractLog = new LoggerProxy();
        abstractLog.method();
    }
}

上面代码中使用了静态代理,增加了代理类来对类的功能进行增强,同时保证对调用者的视图不发生改变。

此外还有动态代理,使用过Spring的同学想必都不会陌生。相比静态代理,动态代理通过动态生成类文件,使得代理类的功能更加灵活,同时避免了项目代码的膨胀。

 

职责链(chain of responsibility)


描述:

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

场景:

某公司欲开发一个软件的在线文档帮助系统,用户可以在任何一个查询环境中输入查询关键字,如果当前查询环境下没有相关的内容,则系统会将查询按照一定的顺序转发给其他查询环境。客户可以定制自己的查询顺序,例如先查询Java关键字,再查询SQL关键字,最后查询UML关键字

在这里插入图片描述

java代码:

package org.crudboy;

abstract class SearchContext {
    protected SearchContext successor;
    public void setSuccessor(SearchContext successor) {
        this.successor = successor;
    }
    public abstract void search(String keyword);
}


class UMLSearchContext extends SearchContext {
    @Override
    public void search(String keyword) {
        if (keyword.contains("UML")){
            System.out.println("查询关键字UML!");
        }else {
            if (this.successor != null){
                System.out.println("无法找到");
            }
        }
    }
}

class JavaSearchContext extends SearchContext {
    @Override
    public void search(String keyword) {
        if (keyword.contains("Java")){
            System.out.println("查询关键字Java!");
        }else {
            if (this.successor != null){
                this.successor.search(keyword); // 找不到会调用下一个context进行查找
            }
        }
    }
}

class SQLSearchContext extends SearchContext {
    @Override
    public void search(String keyword) {
        if (keyword.contains("SQL")){
            System.out.println("查询关键字SQL!");
        }else {
            if (this.successor != null){
                this.successor.search(keyword);
            }
        }
    }
}

public class ResponsibleChain {
    public static void main(String[] args) {
        SearchContext jContext = new JavaSearchContext();
        SearchContext sContext = new SQLSearchContext();
        SearchContext uContext = new UMLSearchContext();
        jContext.setSuccessor(sContext);
        sContext.setSuccessor(uContext);
        String keyword = "UML类图绘制疑惑";
        jContext.search(keyword);
    }
}

通过职责链模式,外部访问者只需要对一个处理者进行处理就可以了,如果其处理失败就会调用下一个处理者(形成一条调用链)。

这样外部访问者只与一个处理者相关。反之,外部者会与多个处理者相关联,如果有许多处理者会非常乱同时不利于代码维护。

在java web中有拦截器filter的应用,其通过filter chain对每个请求或响应进行处理,每个filter在dofiter方法中调用FilterChain.doFilter激活下一个filter,这正是职责链模式的使用。

 

命令模式(command)


描述:
将一个请求(行为)封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。实现对象与行为的解耦

场景:

为了用户使用方便,某系统提供了一系列功能键,用户可以自定义功能键的功能,如功能键FunctionButton可以用于退出系统(SystemExitClass),也可以用于打开帮助界面(DisplayHelpClass)。用户可以通过修改配置文件来改变功能键的用途,现使用命令模式来设计该系统,使得功能键类与功能类之间解耦,相同的功能键可以对应不同的功能。

在这里插入图片描述
 
代码:

package org.crudboy;

class SystemExitClass {
    public void exit(){
        System.out.println("退出系统");
    }
}

class DisplayHelpClass {
    public void display(){
        System.out.println("查看帮助");
    }
}

interface SystemCommand {
    void execute();
}

class ExitCommand implements SystemCommand {
    private SystemExitClass seObj = new SystemExitClass();
    public void execute() {
        seObj.exit();
    }
}

class HelpCommand implements SystemCommand {
    private DisplayHelpClass hcObj = new DisplayHelpClass();
    public void execute() {
        hcObj.display();
    }
}

class FunctionButton {
    private SystemCommand command = null;
    public void setCommand(SystemCommand command) {
        this.command = command;
    }
    public void click() {
        command.execute();
    }
}

public class Command {
    public static void main(String[] args) {
        SystemCommand exitCommand = new ExitCommand();
        SystemCommand helpCommand = new HelpCommand();

        FunctionButton functionButton = new FunctionButton();
        functionButton.setCommand(helpCommand);
        functionButton.click();
        functionButton.setCommand(exitCommand);
        functionButton.click();
    }
}

命令模式的好处是什么?

在上面这个例子中。我们平时写代码大多数情况下都是把这些行为做完对象的一个方法,这样看着也确实更加直观简洁。

但这样当我们需要类功能的拓展时,这时就需要修改源码,这无疑违背了“对拓展开发,对修改关闭”。

而如果将每个行为封装成一个类,再与对象进行关联。那么在需要新增功能时我们只需要新增一个行为类即可。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值