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

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

2.10 模板模式

(1)概念

模板模式通常又叫模板方法模式(Template Method Pattern)是指定义一个算法的骨

架,并允许子类为一个或者多个步骤提供实现。模板方法使得子类可以在不改变算法结

构的情况下,重新定义算法的某些步骤,属于行为性设计模式。

(2)适用场景

1、一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。

2、各子类中公共的行为被提取出来并集中到一个公共的父类中,从而避免代码重复。

3、通常,在微服务架构中一般会建立一个common的module,里面抽取公共的类,然后其他的module来是这个module的子module

(3)代码示例

整体的类图

我们通常上网课看视频,通常网课的步骤是发布预习资料–>制作课件 PPT–>在线直播–> 提 交 课 堂 笔 记 --> 提 交 源 码 --> 布 置 作 业 --> 检 查 作 业 。

首先建立一个抽象类NetworkCourse

  • NetworkCourse 类
package com.alibaba.design.templatemethodpattern.course;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-19:50
 */
public  abstract class NetworkCourse {
    public final void createCourse(){
        //1、发布预习资料
        this.postPreResource();
        //2、制作PPT课件
        this.createPPT();
        //3、在线直播
        this.liveVideo();
        //4、提交课件、课堂笔记
        this.postNote();
        //5、提交源码
        this.postSource();
        //6、布置作业,有些课是没有作业,有些课是有作业的
        //如果有作业的话,检查作业,如果没作业,完成了
        if(needHomeWork()){
            checkHomeWork();
        }
    }
    abstract void checkHomeWork();
    //钩子方法:实现流程的微调
    protected boolean needHomeWork(){return false;}
    final void postSource(){
        System.out.println("提交源代码");
    }
    final void postNote(){
        System.out.println("提交课件和笔记");
    }
    final void liveVideo(){
        System.out.println("直播授课");
    }
    final void createPPT(){
        System.out.println("创建备课PPT");
    }
    final void postPreResource(){
        System.out.println("分发预习资料");
    }
}

上述的钩子方法是设计可以进行流程的微调的,因为通常有些指标不是必须的,比如布置作业,有时候布置了有时候不用布置,因此可以这样来设计。

  • JavaCourse类
package com.alibaba.design.templatemethodpattern.course;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-19:51
 */
public class JavaCourse extends NetworkCourse{
    @Override
    void checkHomeWork() {
        System.out.println("检查java的作业");
    }
}
  • PythonCourse类
package com.alibaba.design.templatemethodpattern.course;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-19:52
 */
public class PythonCourse extends NetworkCourse {
    private boolean needHomeworkFlag = false;
    public PythonCourse(boolean needHomeworkFlag){
        this.needHomeworkFlag = needHomeworkFlag;
    }
    @Override
    void checkHomeWork() {
        System.out.println("检查Python的作业");
    }
    @Override
    protected boolean needHomeWork() {
        return  this.needHomeworkFlag;
    }
}
  • 客户端测试类
package com.alibaba.design.templatemethodpattern.test;
import com.alibaba.design.templatemethodpattern.course.JavaCourse;
import com.alibaba.design.templatemethodpattern.course.NetworkCourse;
import com.alibaba.design.templatemethodpattern.course.PythonCourse;
/**
 * @author zhouyanxiang
 * @create 2020-07-2020/7/29-19:53
 */
public class NetworkCourseTest {
    public static void main(String[] args) {
        System.out.println("---Java架构师课程---");
        NetworkCourse javaCourse = new JavaCourse();
        javaCourse.createCourse();
        System.out.println("---Python课程---");
        NetworkCourse pythonCourse = new PythonCourse(true);
        pythonCourse.createCourse();
    }
}

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

在AbstractList类中的get方法就是一个抽象的方法

在AbstractList类的继承类中的ArrayList中对get方法进行了重写

(5)模板模式的优缺点

  • 优点:
    1、利用模板方法将相同处理逻辑的代码放到抽象父类中,可以提高代码的复用性。
    2、将不同的代码不同的子类中,通过对子类的扩展增加新的行为,提高代码的扩展性。
    3、把不变的行为写在父类上,去除子类的重复代码,提供了一个很好的代码复用平台,
    符合开闭原则。
  • 缺点:
    1、类数目的增加,每一个抽象类都需要一个子类来实现,这样导致类的个数增加。
    2、类数量的增加,间接地增加了系统实现的复杂度。
    3、继承关系自身缺点,如果父类添加新的抽象方法,所有子类都要改一遍。

2.11 空对象模式 (不属于二十三中设计模式中的,这里是扩充一下)

(1)概念

在空对象模式(Null Object Pattern)中,一个空对象取代 NULL 对象实例的检查。Null 对象不是检查空值,而是反应一个不做任何动作的关系。这样的 Null 对象也可以在数据不可用的时候提供默认的行为。

在空对象模式中,我们创建一个指定各种要执行的操作的抽象类和扩展该类的实体类,还创建一个未对该类做任何实现的空对象类,该空对象类将无缝地使用在需要检查空值的地方。

(2)适用场景

满足下列条件时可以使用空对象模式

  • 一个对象需要一个协作对象,但并无具体的协作对象
  • 协作对象不需要做任何事情
  • 需要大量对空值进行判断的时候;

(3)代码示例

我们将创建一个定义操作(在这里,是客户的名称)的 AbstractCustomer 抽象类,和扩展了 AbstractCustomer 类的实体类。工厂类 CustomerFactory 基于客户传递的名字来返回 RealCustomerNullCustomer 对象。

NullPatternDemo,我们的演示类使用 CustomerFactory 来演示空对象模式的用法。

创建一个抽象类。

package com.alibaba.design.nullobjectpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-8:14
 */
public abstract class AbstractCustomer {
    protected String name;
    public abstract boolean isNil();
    public abstract String getName();
}

创建扩展了上述类的实体类。

package com.alibaba.design.nullobjectpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-8:16
 */
public class NullCustomer extends AbstractCustomer {
    @Override
    public boolean isNil() {
        return true;
    }
    @Override
    public String getName() {
        return "Not Available in Customer Database";
    }
}
package com.alibaba.design.nullobjectpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-8:15
 */
public class RealCustomer extends AbstractCustomer {
    public RealCustomer(String name) {
        this.name = name;
    }
    @Override
    public boolean isNil() {
        return false;
    }
    @Override
    public String getName() {
        return name;
    }
}

创建 CustomerFactory 类。

package com.alibaba.design.nullobjectpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-8:17
 */
public class CustomerFactory {
    public static final String[] names = {"Rob", "Joe", "Julie"};
    public static AbstractCustomer getCustomer(String name){
        for (int i = 0; i < names.length; i++) {
            if (names[i].equalsIgnoreCase(name)){
                return new RealCustomer(name);
            }
        }
        return new NullCustomer();
    }
}

客户端测试类

package com.alibaba.design.nullobjectpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-8:17
 */
public class NullPatternDemo {
    public static void main(String[] args) {
        AbstractCustomer customer1 = CustomerFactory.getCustomer("Rob");
        AbstractCustomer customer2 = CustomerFactory.getCustomer("Bob");
        AbstractCustomer customer3 = CustomerFactory.getCustomer("Julie");
        AbstractCustomer customer4 = CustomerFactory.getCustomer("Laura");
        System.out.println("Customers");
        System.out.println(customer1.getName());
        System.out.println(customer2.getName());
        System.out.println(customer3.getName());
        System.out.println(customer4.getName());
    }
}

输出结果:

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

commons-lang3 jar包里面的StringUtils

包含了isNotEmpty()就是对String类型的对象的空值判断,我们通常可以用他对字符串进行空值判断处理

(5)空对象模式的优缺点

  • 优点
    可以加强系统的稳固性,能有效防止空指针报错对整个系统的影响;
    不依赖客户端便可以保证系统的稳定性;
  • 缺点
    需要编写较多的代码来实现空值的判断,从某种方面来说不划算;

2.12 访问者模式

(1)概念

在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。

主要解决:稳定的数据结构和易变的操作耦合问题。

何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。

如何解决:在被访问的类里面加一个对外提供接待访问者的接口。

关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。

(2)适用场景

1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。

2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。

注意事项:访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。

(3)代码示例

我们将创建一个定义接受操作的 ComputerPart 接口。KeyboardMouseMonitorComputer 是实现了 ComputerPart 接口的实体类。我们将定义另一个接口 ComputerPartVisitor,它定义了访问者类的操作。Computer 使用实体访问者来执行相应的动作。

VisitorPatternDemo,我们的演示类使用 ComputerComputerPartVisitor 类来演示访问者模式的用法。

定义一个表示元素的接口。

  • ComputerPart
package com.alibaba.design.visitorpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-8:54
 */
public interface ComputerPart {
    public void accept(ComputerPartVisitor computerPartVisitor);
}

定义一个表示访问者的接口。

  • ComputerPartVisitor
package com.alibaba.design.visitorpattern;
import com.alibaba.design.visitorpattern.Mouse;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-8:54
 */
public interface ComputerPartVisitor {
    public void visit(Computer computer);
    public void visit(Mouse mouse);
    public void visit(Keyboard keyboard);
    public void visit(Monitor monitor);
}

创建扩展了ComputerPart 的实体类。

  • Computer
package com.alibaba.design.visitorpattern;
import com.alibaba.design.visitorpattern.Mouse;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-8:56
 */
public class Computer implements ComputerPart  {
    ComputerPart[] parts;
    public Computer(){
        parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
    }
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        for (int i = 0; i < parts.length; i++) {
            parts[i].accept(computerPartVisitor);
        }
        computerPartVisitor.visit(this);
    }
}
  • Keyboard
package com.alibaba.design.visitorpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-8:55
 */
public class Keyboard implements ComputerPart {
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}
  • Monitor
package com.alibaba.design.visitorpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-9:05
 */
public class Monitor implements ComputerPart {
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}
  • Mouse
package com.alibaba.design.visitorpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-9:05
 */
public class Mouse implements ComputerPart {
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}

创建实现了上述类的实体访问者。

  • ComputerPartDisplayVisitor
package com.alibaba.design.visitorpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-9:06
 */
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
    @Override
    public void visit(Computer computer) {
        System.out.println("Displaying Computer.");
    }
    @Override
    public void visit(Mouse mouse) {
        System.out.println("Displaying Mouse.");
    }
    @Override
    public void visit(Keyboard keyboard) {
        System.out.println("Displaying Keyboard.");
    }
    @Override
    public void visit(Monitor monitor) {
        System.out.println("Displaying Monitor");
    }
}

客户端测试类

package com.alibaba.design.visitorpattern;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/2-9:08
 */
public class VisitorPatternDemo {
    public static void main(String[] args) {
        ComputerPart computer = new Computer();
        computer.accept(new ComputerPartDisplayVisitor());
    }
}

输出结果:

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

在Spring中的应用:

它的具体实现都交给了valueResolver来实现

方法visitBeanDefinition实现了不同的visi方法t来对相同的数据进行不同的处理

(5)访问者模式的优缺点

优点:

1、符合单一职责原则。

2、优秀的扩展性。

3、灵活性。

缺点:

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