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、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。

相关文章
|
23天前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
48 24
|
5天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
41 2
|
19天前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
55 5
|
19天前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
46 5
|
20天前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
21天前
|
Java API 开发者
Java中的Lambda表达式:简洁代码的利器####
本文探讨了Java中Lambda表达式的概念、用途及其在简化代码和提高开发效率方面的显著作用。通过具体实例,展示了Lambda表达式如何在Java 8及更高版本中替代传统的匿名内部类,使代码更加简洁易读。文章还简要介绍了Lambda表达式的语法和常见用法,帮助开发者更好地理解和应用这一强大的工具。 ####
|
25天前
|
Java API Maven
商汤人像如何对接?Java代码如何写?
商汤人像如何对接?Java代码如何写?
34 5
|
26天前
|
Java
在Java中实现接口的具体代码示例
可以根据具体的需求,创建更多的类来实现这个接口,以满足不同形状的计算需求。希望这个示例对你理解在 Java 中如何实现接口有所帮助。
41 1
|
1月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
36 4
|
18天前
|
安全 Java API
Java中的Lambda表达式:简化代码的现代魔法
在Java 8的发布中,Lambda表达式的引入无疑是一场编程范式的革命。它不仅让代码变得更加简洁,还使得函数式编程在Java中成为可能。本文将深入探讨Lambda表达式如何改变我们编写和维护Java代码的方式,以及它是如何提升我们编码效率的。