设计模式(3)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiaoyi52/article/details/81347285

2.3 行为型模式

行为型模式一共有11种,分别是模板方法模式(Template Method),策略模式(Strategy),命令模式(Command),中介者模式(Mediator),观察者模式(Observer),迭代器模式(Iterator),访问者模式(Visiter),责任链模式(Chain of Responsibility),备忘录模式(Memento),状态模式(State)和解释器模式(Interpreter)。

2.3.1 模板方法模式

模板方法模式的名称就能说明这个模式的特点。模板方法,说明这个方法是一个模板,是一个通用的方法。所有的调用者都需要调用这个方法,而且这个方法里面很多步骤都是公用的,固定的。当然,既然被多个调用者调用,说明肯定有某个或几个步骤实现是不一样的。因此这些不一样的实现步骤就可以定义为抽象方法,让调用者自己去实现。

模板方法的描述是:定义一个操作中算法的骨架,而将一些步骤延迟到子类中,使子类可以重定义算法的某些特定步骤而不改变该算法的结构。

模板方法模式是行为型模式中最简单的模式之一。

2.3.2 策略模式

策略模式其实很简单,就是根据不同的条件调用不同的接口实现。不用策略模式的话,用if-else就也可以实现,如if a then doSomethingWithA; if b then doSomthingWithB; if c…。使用策略模式后就是抽象出一个策略接口,定义一个接口方法doSomething。然后由不同的策略实现者来实现接口的doSomething方法。根据不同的条件获取到不同的策略实例进行调用。

策略模式的描述是:定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换。策略模式使算法可独立于使用它的客户而变化。

2.3.3 观察者模式

观察者模式描述:观察者模式定义了一种一对多的关系,让多个观察者监听某一主题对象,当这个主题对象的状态变化时,会通知所有观察者对象,以便观察者对象进行某种应对。
观察者模式一共有四中角色,分别是抽象主题,具体主题,抽象观察者,具体观察者。抽象主题提供注册、注销和通知观察者的方法 (具体的例子可以看看参考资料1)。

2.3.4 责任链模式

责任链模式的描述:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到链上的某一个对象处理此请求。

Servelet中的过滤器Filter就使用了责任链模式。在一个应用中通常有多个过滤器,每个过滤器的作用不同,如字符编码过滤器,权限控制过滤器等等。一个请求过来,根据过滤器的先后顺序分别对该请求进行处理,前面的过滤器处理完成之后转发给后面的过滤器进行处理,一直到所有的过滤器处理完成。这些过滤器就形成了一个链,请求沿着这条链流转。

下面来看一个例子。
假设某论坛需要对用户留言进行处理,过滤掉其中的表情符号和敏感字符,如留言“JAVA是最好的语言,不接受反驳?(这里是笑脸表情符,无法显示)”,其中JAVA和笑脸符号需要过滤。可以设计两个过滤器,分别用于过滤敏感字符和表情符号。不使用责任链的情况下的实现方式:

public interface Filter {
    String doFilter(String str);
}

public class SensitiveFilter implements Filter{
    @Override
    public String doFilter(String str) {
        String sensitive = "JAVA";
        if (str.contains(sensitive)) {
            str = str.replace(sensitive, "**");
        }
        System.out.println("敏感词过滤后:" + str);
        return str;
    }
}

public class EmojiFilter implements Filter {
    @Override
    public String doFilter(String str) {
        str = str.replaceAll("[\\ud800\\udc00-\\udbff\\udfff\\ud800-\\udfff]", "*");
        System.out.println("过滤掉表情符号后:" + str);
        return str;
    }
}

调用:

public class Client {
    public static void main(String[] args) {
        String str = "JAVA是最好的语言,不接受反驳\uD83D\uDE00";
        Filter[] filters = {new SensitiveFilter(), new EmojiFilter()};
        for (Filter filter : filters) {
            str = filter.doFilter(str);
        }
    }
}

输出:

敏感词过滤后:**是最好的语言,不接受反驳?
过滤掉表情符号后:**是最好的语言,不接受反驳*

上述例子中主要有两个角色,过滤器接口和具体过滤器。在客户端中控制过滤器的调用,不存在链的概念,所以不是责任链模式。如果使用责任链模式应该怎么实现呢?显然应该增加一个角色:过滤器链FilterChain,如下所示:

public class FilterChain implements Filter {
    public List<Filter> filters = new ArrayList<>();

    public FilterChain addFilter(Filter filter) {
        filters.add(filter);
        return this;
    }

    public String doFilter(String str) {
        for (Filter filter : filters) {
            str = filter.doFilter(str);
        }
        return str;
    }
}

客户端调用:

public class Client {
    public static void main(String[] args) {
        String str = "JAVA是最好的语言,不接受反驳\uD83D\uDE00";
        FilterChain filterChain = new FilterChain().addFilter(new SensitiveFilter()).addFilter(new EmojiFilter());
        filterChain.doFilter(str);
    }
}

经改造后,过滤器由filterChain进行调用,控制权交给filterChain了,这是一个简单的责任链。这个责任链中实际上是有一个控制中心的,即filterChain,控制中心决定处理对象的调用。

责任链在过滤器中的应用
实际servlet过滤器中的责任链比上面的例子要复杂一点。上述例子中,有一个控制中心,请求由控制中心进行分发,交给每一个处理器进行处理,处理完成之后结束。其结构如下:
这里写图片描述

在过滤器中,请求是由过滤器进行转发的。对上文中的例子进行改造:

public interface Filter {
    void doFilter(String request, String response, FilterChain filterChain);
}

public class SensitiveFilter implements Filter{
    @Override
    public void doFilter(String request, String response, FilterChain filterChain) {
        String sensitive = "JAVA";
        if (request.contains(sensitive)) {
            request = request.replace(sensitive, "**");
        }
        System.out.println("敏感词过滤后:" + request);
        filterChain.doFilter(request, response, filterChain);
    }
}

public class EmojiFilter implements Filter {

    @Override
    public void doFilter(String str, String response, FilterChain filterChain) {
        str = str.replaceAll("[\\ud800\\udc00-\\udbff\\udfff\\ud800-\\udfff]", "*");
        System.out.println("过滤掉表情符号后:" + str);
        filterChain.doFilter(str, response, filterChain);
    }
}

public class FilterChain implements Filter {
    public List<Filter> filters = new ArrayList<>();
    int index = 0;

    public FilterChain addFilter(Filter filter) {
        filters.add(filter);
        return this;
    }

    @Override
    public void doFilter(String str, String response, FilterChain filterChain) {
        if (index == filters.size()) {
            return;
        }
        Filter filter = filters.get(index);
        index++;
        filter.doFilter(str, response, filterChain);
    }
}

调用和输出:

public class Client {
    public static void main(String[] args) {
        String str = "JAVA是最好的语言,不接受反驳\uD83D\uDE00";
        String response = null;
        FilterChain filterChain = new FilterChain().addFilter(new SensitiveFilter()).addFilter(new EmojiFilter());
        filterChain.doFilter(str, response, filterChain);
    }
}
敏感词过滤后:**是最好的语言,不接受反驳?
过滤掉表情符号后:**是最好的语言,不接受反驳*

过滤器链中,当前过滤器处理完request后调用filterChain的doFilter方法,该方法会继续找到下一个过滤器进行调用。下一个过滤器处理完request之后再次调用filterChain的doFilter方法,继续分发给下一个过滤器。其调用结构如下:
这里写图片描述

在这个调用过程中filterChain实际上只是负责找到下一个过滤器,将请求传给该过滤器处理。进一步简化为:
这里写图片描述

这样从左到右是处理request的,从右到左是处理response的。

参考资料

1.https://www.cnblogs.com/luohanguo/p/7825656.html

猜你喜欢

转载自blog.csdn.net/xiaoyi52/article/details/81347285