Java代码设计模式讲解二十三种设计模式(四)

简介: Java代码设计模式讲解二十三种设计模式

2.4 迭代器模式

(1)概念

迭代器模式(Iterator Pattern)是 Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。

迭代器模式属于行为型模式。

(2)适用场景

1、访问一个聚合对象的内容而无须暴露它的内部表示。

2、需要为聚合对象提供多种遍历方式。

3、为遍历不同的聚合结构提供一个统一的接口。

(3)代码示例

我们将创建一个叙述导航方法的 Iterator 接口和一个返回迭代器的 Container 接口。实现了 Container 接口的实体类将负责实现 Iterator 接口。

IteratorPatternDemo,我们的演示类使用实体类 NamesRepository 来打印 NamesRepository 中存储为集合的 Names

创建接口:

package com.alibaba.design.iteratorpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/1-21:16
 */
public interface Iterator {
    public boolean hasNext();
    public Object next();
}
• 12
package com.alibaba.design.iteratorpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/1-21:16
 */
public interface Container  {
    public Iterator getIterator();
}

创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator

package com.alibaba.design.iteratorpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/1-21:22
 */
public class NameRepository implements Container {
    public String []names = {"Robert" , "John" ,"Julie" , "Lora"};
    @Override
    public Iterator getIterator() {
        return new NameIterator();
    }
    private class NameIterator implements Iterator {
        int index;
        @Override
        public boolean hasNext() {
            if (index < names.length){
                return true;
            }else {
                return false;
            }
        }
        @Override
        public Object next() {
            if(this.hasNext()){
                return names[index++];
            }
            return null;
        }
    }
}

客户端测试类

package com.alibaba.design.iteratorpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/1-21:23
 */
public class IteratorPatternDemo {
    public static void main(String[] args) {
        NameRepository namesRepository = new NameRepository();
        for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){
            String name = (String)iter.next();
            System.out.println("Name : " + name);
        }
    }
}

输出示例:

(4)该模式在源码中的体现

java.util.Iterator迭代器就是用到了迭代器模式

(5)迭代器模式的优缺点

  • 优点:
    1、它支持以不同的方式遍历一个聚合对象。
    2、迭代器简化了聚合类。
    3、在同一个聚合上可以有多个遍历。
    4、在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。
  • 缺点:
    由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

2.5 观察者模式

(1) 概念

观察者模式(Observer Pattern)定义了对象之间的一对多依赖,让多个观察者对象同时监听一个主体对象,当主体对象发生变化时,它的所有依赖者(观察者)都会收到通知并更新,属于行为型模式。观察者模式有时也叫做发布订阅模式。

(2)适用场景

观察者模式主要用于在关联行为之间建立一套触发机制的场景。观察者模式在现实生活应用也非常广泛,

比如:微信朋友圈动态通知、GPser 生态圈消息通知、邮件通知、广播通知、桌面程序的事件响应等(如下图)。

如果有设置指定老师回答,对应的老师就会收到邮件通知,这就是观察者模式的一种应用场

景。我们可能会想到 MQ,异步队列等,其实 JDK 本身就提供这样的 API。

(3) 代码示例

我们用代码来还原一下这样一个应用场景,创建 GPer 类:

package com.alibaba.design.observerpattern.gperadvice;
import java.util.Observable;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-9:42
 */
public class GPer extends Observable {
    private String name = "GPer生态圈";
    private static GPer gper = null;
    private GPer(){}
    public static GPer getInstance(){
        if(null == gper){
            gper = new GPer();
        }
        return gper;
    }
    public String getName() {
        return name;
    }
    public void publishQuestion(Question question){
        System.out.println(question.getUserName() + "在" + this.name + "上提交了一个问题。");
        setChanged();
        notifyObservers(question);
    }
}

创建问题 Question 类:

package com.alibaba.design.observerpattern.gperadvice;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-9:43
 */
public class Question {
    private String userName;
    private String content;
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
}

创建老师 Teacher 类:

package com.alibaba.design.observerpattern.gperadvice;
import java.util.Observable;
import java.util.Observer;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-9:43
 */
public class Teacher implements Observer {
    private String name;
    public Teacher(String name){
        this.name = name;
    }
    @Override
    public void update(Observable o, Object arg) {
        GPer gper = (GPer)o;
        Question question = (Question)arg;
        System.out.println("===============================");
        System.out.println(name + "老师,你好!\n" +
                "您收到了一个来自“" + gper.getName() + "”的提问,希望您解答,问题内容如下:\n" +
                question.getContent() + "\n" +
                "提问者:" + question.getUserName());
    }
}

客户端测试代码

package com.alibaba.design.observerpattern.gperadvice;
import java.util.Observer;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-9:44
 */
public class ObserverTest {
    public static void main(String[] args) {
        GPer gper = GPer.getInstance();
        Teacher tom = new Teacher("Tom");
        Teacher mic = new Teacher("Jerry");
        //这为没有@Tom老师
        Question question = new Question();
        question.setUserName("小明");
        question.setContent("观察者设计模式适用于哪些场景?");
        gper.addObserver(tom);
        gper.addObserver(mic);
        gper.publishQuestion(question);
    }
}

(4) 模式在源码中的体现

来看一下 Spring 中的 ContextLoaderListener 实现了 ServletContextListener 接口,ServletContextListener 接口又继承了 EventListener,在 JDK 中 EventListener 有非常广泛的应用。我们可以看一下源代码,ContextLoaderListener:

package org.springframework.web.context;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
    public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
    public ContextLoaderListener() {
    }
    public ContextLoaderListener(WebApplicationContext context) {
      super(context);
    }
    @override     
    public void contextInitialized(ServletContextEvent event) {
      this.initWebApplicationContext(event.getServletContext());
    }
    @override    
    public void contextDestroyed(ServletContextEvent event) {
      this.closeWebApplicationContext(event.getServletContext());
      ContextCleanupListener.cleanupAttributes(event.getServletContext());
    }
}

ServletContextListener

package javax.servlet;
import java.util.EventListener;
public interface ServletContextListener extends EventListener {
    public void contextInitialized(ServletContextEvent sce);
    public void contextDestroyed(ServletContextEvent sce);
}

EventListener

package java.util;
public interface EventListener {
}

(5)基于 Guava API 轻松落地观察者模式

Guava是一种基于开源的Java库,Google Guava源于2007年的"Google Collections Library"。这个库是为了方便编码,并减少编码错误。这个库用于提供集合,缓存,支持原语句,并发性,常见注解,字符串处理,I/O和验证的实用方法。

在这里,我还推荐给大家一个实现观察者模式非常好用的框架。API 使用也非常简单,举

个例子,先引入jar包:guava-20.jar

这里建议去maven下载这个

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>

创建侦听事件 GuavaEvent:

package com.alibaba.design.observerpattern.guava;
import com.google.common.eventbus.Subscribe;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-9:59
 */
public class GuavaEvent {
    @Subscribe
    public void subscribe(String str){
        System.out.println("执行subscribe方法,传入的参数是:" + str);
    }
}

客户端测试代码:

package com.alibaba.design.observerpattern.guava;
import com.google.common.eventbus.EventBus;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/30-9:59
 */
public class GuavaEventTest {
    public static void main(String[] args) {
        //消息总线
        EventBus eventBus = new EventBus();
        GuavaEvent guavaEvent = new GuavaEvent();
        eventBus.register(guavaEvent);
        eventBus.post("Tom");
    }
}

(6) 观察者模式的优缺点

  • 优点:
    1、观察者和被观察者之间建立了一个抽象的耦合。
    2、观察者模式支持广播通信。
  • 缺点:
    1、观察者之间有过多的细节依赖、提高时间消耗及程序的复杂度。
    2、使用要得当,要避免循环调用。

2.6 中介者模式

(1)概念

中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。

图片来源:https://blog.csdn.net/ZixiangLi/article/details/86228684

(2)适用场景

1、系统中对象之间存在比较复杂的引用关系,导致它们之间的依赖关系结构混乱而且难以复用该对象。

2、想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。

注意事项:不应当在职责混乱的时候使用。

**主要解决:**对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。

**何时使用:**多个类相互耦合,形成了网状结构。

**如何解决:**将上述网状结构分离为星型结构。

**关键代码:**对象 Colleague 之间的通信封装到一个类中单独处理。

(3)代码示例

我们通过聊天室实例来演示中介者模式。实例中,多个用户可以向聊天室发送消息,聊天室向所有的用户显示消息。我们将创建两个类 ChatRoomUserUser 对象使用 ChatRoom 方法来分享他们的消息。

MediatorPatternDemo,我们的演示类使用 User 对象来显示他们之间的通信。

创建中介类。

package com.alibaba.design.mediatorpattern;
import java.util.Date;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/1-21:50
 */
public class ChatRoom {
    public static void showMessage(User user, String message){
        System.out.println(new Date().toString()
                + " [" + user.getName() +"] : " + message);
    }
}

创建 user 类。

package com.alibaba.design.mediatorpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/1-21:51
 */
public class User {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public User(String name){
        this.name  = name;
    }
    public void sendMessage(String message){
        ChatRoom.showMessage(this,message);
    }
}

使用 User 对象来显示他们之间的通信。

package com.alibaba.design.mediatorpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/1-21:53
 */
public class MediatorPatternDemo {
    public static void main(String[] args) {
        User robert = new User("Robert");
        User john = new User("John");
        robert.sendMessage("Hi! John!");
        john.sendMessage("Hello! Robert!");
    }
}

(4)该模式在源码中的体现

在java.util.Timer中

timer是一个中介者,它持有新创建到TimerTask的引用,timer负责执行TimerTask的定时任务。不同的TimerTask只知道自己的定时任务,而不清楚其他的TimerTask任务,但是都认识Timer这个中间者对象

在线程方面也用到了这个模式

java.util.concurrent.Executor#execute(Runnable command)

java.util.concurrent.ExecutorService#submit(Runnable command)

exec是一个中介者,它持有Runnable的引用,exec是一个异步任务执行者,它负责执行Runnable任务。

Executor exec = Executors.newFixedThreadPool(100);
    exec.execute(new Runnable() {
      @Override
      public void run() {
        System.out.println("nice to meet u");
      }
    });
    exec.execute(new Runnable() {
      @Override
      public void run() {
        System.out.println("nice to meet u too");
      }
    });

(5)中介者模式的优缺点

  • 优点:
    1、降低了类的复杂度,将一对多转化成了一对一。
    2、各个类之间的解耦。
    3、符合迪米特原则。
  • 缺点:
    中介者会庞大,变得复杂难以维护。


相关文章
|
2天前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
|
13天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
16天前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###
|
16天前
|
XML 安全 Java
Java反射机制:解锁代码的无限可能
Java 反射(Reflection)是Java 的特征之一,它允许程序在运行时动态地访问和操作类的信息,包括类的属性、方法和构造函数。 反射机制能够使程序具备更大的灵活性和扩展性
26 5
Java反射机制:解锁代码的无限可能
|
9天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
24 1
|
13天前
|
jenkins Java 测试技术
如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例详细说明
本文介绍了如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例,详细说明了从 Jenkins 安装配置到自动构建、测试和部署的全流程。文中还提供了一个 Jenkinsfile 示例,并分享了实践经验,强调了版本控制、自动化测试等关键点的重要性。
42 3
|
18天前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
50 10
|
14天前
|
分布式计算 Java MaxCompute
ODPS MR节点跑graph连通分量计算代码报错java heap space如何解决
任务启动命令:jar -resources odps-graph-connect-family-2.0-SNAPSHOT.jar -classpath ./odps-graph-connect-family-2.0-SNAPSHOT.jar ConnectFamily 若是设置参数该如何设置
|
12天前
|
Java
Java代码解释++i和i++的五个主要区别
本文介绍了前缀递增(++i)和后缀递增(i++)的区别。两者在独立语句中无差异,但在赋值表达式中,i++ 返回原值,++i 返回新值;在复杂表达式中计算顺序不同;在循环中虽结果相同但使用方式有别。最后通过 `Counter` 类模拟了两者的内部实现原理。
Java代码解释++i和i++的五个主要区别
|
20天前
|
搜索推荐 Java 数据库连接
Java|在 IDEA 里自动生成 MyBatis 模板代码
基于 MyBatis 开发的项目,新增数据库表以后,总是需要编写对应的 Entity、Mapper 和 Service 等等 Class 的代码,这些都是重复的工作,我们可以想一些办法来自动生成这些代码。
28 6