文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

面试官:JDK中都用了哪些设计模式?

2024-11-29 19:45

关注

设计模式是前辈们经过实践验证总结的解决方案,帮助我们构建出更具可维护性、可扩展性和可读性的代码。当然,在面试的过程中,也会或多或少的被问到。那么今天,我们就来看一道设计模式中的常见面试问题:JDK 中都用了哪些设计模式?

我按照大家比较熟悉且好理解的方式,把  JDK 中使用的设计模式总结了一下,如下图所示:

那么,接下来我们一个个来看。

1.单例模式

单例模式保证一个类只有一个实例,并提供一个全局访问点。

Runtime 类使用了单例模式,如下源码可知:

public class Runtime {
    private static final Runtime currentRuntime = new Runtime();
    private static Version version;
    
    public static Runtime getRuntime() {
        return currentRuntime;
    }
    
    private Runtime() {}
    // 省略其他源码
}

从以上源码可以看出,Runtime 使用的饿汉方式实现了单例模式。

2.工厂模式

工厂模式提供了一种将对象创建的过程封装在一个单独的类中的方法,这个类就是工厂类。

线程池中的所有线程的创建都是通过工厂创建的,使用的就是工厂模式,具体源码如下:

3.代理模式

代理模式是一种为其他对象提供一种代理以控制对这个对象的访问的设计模式。代理对象在客户端和目标对象之间起到中介的作用,并且可以去掉客户不能看到的内容和服务或者添加客户需要的额外服务。

JDK 内置了动态代理的功能,动态代理是代理模式的一种实现,它是由 java.lang.reflect.Proxy 类提供的。

Proxy 使用 Demo 如下:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 1.接口
interface Subject {
    void doSomething();
}

// 2.目标类(被代理类)
class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject is doing something");
    }
}

// 3.动态代理类
class DynamicProxyHandler implements InvocationHandler {
    private Object target;
    DynamicProxyHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before calling method");
        Object result = method.invoke(target, args);
        System.out.println("After calling method");
        return result;
    }
}

public class JDKProxyDemo {
    public static void main(String[] args) {
        // 创建真实对象
        Subject realSubject = new RealSubject();
        // 创建动态代理处理器
        InvocationHandler handler = new DynamicProxyHandler(realSubject);
        // 创建代理对象
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
            realSubject.getClass().getClassLoader(),
            realSubject.getClass().getInterfaces(),
            handler);
        // 调用代理对象的方法
        proxySubject.doSomething();
    }
}

4.迭代器模式

迭代器模式能够提供一种简单的方法来遍历容器中的每个元素。通过迭代器,用户可以轻松地访问容器中所有的元素,简化了编程过程。

Iterable 就是标准的迭代器模式,Collection 就是 Iterator 的子类,它的使用代码如下:

import java.util.ArrayList;
import java.util.Iterator;

public class IteratorDemo {
    public static void main(String[] args) {
        // 创建一个 ArrayList 并添加元素
        ArrayList list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Orange");

        // 获取迭代器
        Iterator iterator = list.iterator();

        // 使用迭代器遍历集合
        while (iterator.hasNext()) {
            String fruit = iterator.next();
            System.out.println("Fruit: " + fruit);
        }
    }
}

5.模版方法模式

模板方法模式(Template Method Pattern)定义了一个操作中的算法骨架,将一些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

在 AQS(AbstractQueuedSynchronizer) 中,acquire 方法和 release 方法使用了模板方法模式。

这些方法之所以被认为是模板方法模式,是因为它们定义了一个操作的基本框架或流程,但其中的某些关键步骤被设计为抽象方法,留给子类去具体实现。

以 acquire 方法为例,它大致的流程包括尝试获取资源、如果获取失败则将当前线程加入等待队列、阻塞线程等步骤。但是具体如何判断能否获取资源(通过调用 tryAcquire 方法),以及在获取失败后的一些处理细节,是由子类去实现的,具体源码如下:

protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}

例如,基于 AQS 实现的 ReentrantLock 中就重写了 tryAcquire 方法,实现源码如下:

6.装饰器模式

装饰器模式是在不修改原对象的基础上,动态地给对象添加额外功能的设计模式。

BufferedInputStream 就是典型装饰器模式,当使用普通的 InputStream 读取数据时,每次可能都会进行实际的 I/O 操作,而 BufferedInputStream 会先将一部分数据读入缓冲区,后续的读取操作可以直接从缓冲区获取,减少了实际的 I/O 次数。

例如以下代码:

InputStream inputStream = new FileInputStream("file.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);

BufferedInputStream 并没有改变 FileInputStream 的基本结构和接口,只是为其添加了缓冲的特性

7.策略模式

策略模式定义了一系列可互换的算法,并将每一个算法封装起来,使它们可以互相替换。

Comparator 是策略模式的一个典型例子,Comparator 接口定义了一个比较两个对象的方法 compare(T o1, T o2)。这个接口允许用户定义不同的比较策略,使得我们可以灵活地改变排序或比较逻辑。

例如以下示例代码:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class StrategyPatternExample {
    static class Person {
        private String name;
        private int age;
        // 忽略 Setter、Getter 等方法
    }
    // 按照年龄升序排列
    static class AgeComparator implements Comparator {
        @Override
        public int compare(Person p1, Person p2) {
            return Integer.compare(p1.getAge(), p2.getAge());
        }
    }
    // 按照姓名降序排列
    static class NameDescendingComparator implements Comparator {
        @Override
        public int compare(Person p1, Person p2) {
            return p2.getName().compareTo(p1.getName());
        }
    }
    public static void main(String[] args) {
        ArrayList people = new ArrayList<>();
        people.add(new Person("Alice", 30));
        people.add(new Person("Bob", 25));
        people.add(new Person("Charlie", 35));

        // 使用年龄升序的策略
        Collections.sort(people, new AgeComparator());

        // 使用姓名降序的策略
        Collections.sort(people, new NameDescendingComparator());
    }
}

8.建造者模式

建造者模式是一种创建型设计模式,用于通过一系列的步骤来创建复杂的对象。它将对象的构建过程与其表示相分离,使得同样的构建过程可以创建不同的表示。

在 JDK 中,使用建造者模式的常见例子是 StringBuilder 和 StringBuffer 类。

虽然这两个类本身不是传统意义上的建造者模式实现(因为建造者模式通常用于构建不同的表示或者不同部分的同一个对象),它们提供了一种链式调用的方式来构建和修改字符串,这在某种程度上体现了建造者模式的思想。

例如以下代码:

public class StringBuilderDemo {  
    public static void main(String[] args) {  
        // 使用 StringBuilder 构建和修改字符串  
        StringBuilder builder = new StringBuilder();  
        builder.append("Hello")  
        .append(", ")  
        .append("world")  
        .append("!")  
        .insert(7, "beautiful ")  
        .deleteCharAt(13);  

        // 输出构建和修改后的字符串  
        System.out.println(builder.toString());  
        // 输出: Hello, beautiful world!  
    }  
}

StringBuilder 通过链式调用 append、insert 和 deleteCharAt 方法来逐步构建和修改字符串。这种方式使得构建和修改字符串的过程更加流畅和易于阅读。

来源:磊哥和Java内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯