Android第六次面试总结(Java设计模式篇一)

发布于:2025-03-25 ⋅ 阅读:(34) ⋅ 点赞:(0)

   单例模式属于创建型设计模式,它保证一个类仅有一个实例,并且提供一个全局访问点来获取该实例。下面为你详细阐述单例模式的好处和坏处。

好处

  1. 资源优化:单例模式能保证一个类只有一个实例,这对于那些创建和销毁开销大的对象(像数据库连接、线程池、缓存等)非常有用。比如,数据库连接频繁创建和销毁会消耗大量资源,使用单例模式可以确保只创建一个数据库连接实例,减少资源浪费。
  2. 全局访问:单例模式提供了一个全局访问点,使得系统中任何地方都可以访问该实例。这在多个模块需要共享同一个资源时非常方便,比如日志记录器,所有模块都可以通过单例日志记录器来记录日志。
  3. 数据一致性:由于只有一个实例存在,所有对该实例的操作都是针对同一个对象,避免了多个实例导致的数据不一致问题。例如,在多线程环境下,单例模式可以确保对共享资源的操作是线程安全的。

坏处

  1. 违反单一职责原则:单例模式的类既负责自身实例的创建和管理,又负责业务逻辑的实现,这违反了单一职责原则,使得类的职责过重,不利于代码的维护和扩展。
  2. 扩展性差:单例模式通常没有抽象层,难以进行扩展和修改。如果需要改变单例类的行为,可能需要直接修改类的代码,这违反了开闭原则。
  3. 多线程问题:虽然单例模式可以在多线程环境下保证只有一个实例,但实现线程安全的单例模式需要额外的同步机制,这会增加系统的复杂性和性能开销。
  4. 单元测试困难:单例模式的全局访问特性使得单元测试变得困难。因为单例类的状态可能会影响其他测试用例的执行结果,而且在测试过程中很难模拟不同的单例实例。

  工厂模式概述

工厂模式是一种创建型设计模式,它提供了一种创建对象的方式,将对象的创建和使用分离。其核心思想是定义一个创建对象的接口,让子类决定实例化哪个类。这样做的好处是提高了代码的可维护性和可扩展性,使得代码更符合开闭原则,即对扩展开放,对修改关闭。

  线程池中的工厂模式

在 Java 里,线程池用到了工厂模式,特别是在创建线程时。java.util.concurrent 包中的 ThreadFactory 接口就是工厂模式的体现。下面详细讲解线程池中的工厂模式:

1. ThreadFactory 接口

ThreadFactory 接口定义了创建线程的方法,代码如下:

public interface ThreadFactory {
    Thread newThread(Runnable r);
}

该接口只有一个方法 newThread,它接收一个 Runnable 对象作为参数,返回一个新的 Thread 对象。通过实现这个接口,我们可以自定义线程的创建逻辑。

2. 线程池使用 ThreadFactory

ThreadPoolExecutor 类在创建线程池时可以传入一个 ThreadFactory 对象,以此来指定线程的创建方式。以下是 ThreadPoolExecutor 的构造函数:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         threadFactory, defaultHandler);
}

这里的 threadFactory 参数就是用来创建线程的工厂。

3. 示例代码

下面是一个使用自定义 ThreadFactory 的线程池示例:

import java.util.concurrent.*;

// 自定义 ThreadFactory
class CustomThreadFactory implements ThreadFactory {
    private final String namePrefix;
    private int counter = 0;

    public CustomThreadFactory(String namePrefix) {
        this.namePrefix = namePrefix;
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r, namePrefix + "-" + counter++);
        // 可以在这里设置线程的其他属性,如优先级、是否为守护线程等
        thread.setPriority(Thread.NORM_PRIORITY);
        return thread;
    }
}

public class ThreadPoolFactoryExample {
    public static void main(String[] args) {
        // 创建自定义 ThreadFactory
        ThreadFactory customFactory = new CustomThreadFactory("CustomThread");

        // 创建线程池
        ExecutorService executorService = new ThreadPoolExecutor(
                2,
                5,
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(),
                customFactory
        );

        // 提交任务
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            executorService.submit(() -> {
                System.out.println("Task " + taskId + " is running on thread: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskId + " is completed.");
            });
        }

        // 关闭线程池
        executorService.shutdown();
    }
}
代码解释
  1. 自定义 ThreadFactoryCustomThreadFactory 类实现了 ThreadFactory 接口,在 newThread 方法中创建了一个新的线程,并为线程设置了自定义的名称和优先级。
  2. 创建线程池:在 main 方法中,我们创建了一个 ThreadPoolExecutor 线程池,并传入了自定义的 ThreadFactory
  3. 提交任务:通过 executorService.submit 方法提交了 5 个任务,每个任务会打印当前运行的线程名称和任务完成信息。
  4. 关闭线程池:使用 executorService.shutdown 方法关闭线程池。

工厂模式在线程池中的优势

  • 可定制性:能够自定义线程的创建逻辑,例如设置线程的名称、优先级、是否为守护线程等。
  • 代码复用:可以在多个线程池中复用同一个 ThreadFactory,提高代码的复用性。
  • 可维护性:将线程的创建和使用分离,使得代码更易于维护和扩展。

   建造者模式的核心思想是将复杂对象的构建和表示分离,让相同的构建过程能创建出不同的表示。在 Android 和 Java 开发中,OkHttp 和 Retrofit 这两个网络请求库就很好地运用了建造者模式。下面将结合它们详细讲解。

OkHttp 中的建造者模式

OkHttp 是一个高效的 HTTP 客户端,它使用建造者模式来配置 OkHttpClient 实例。OkHttpClient 有很多可配置的属性,例如连接超时时间、读取超时时间、拦截器等。通过建造者模式,你可以逐步设置这些属性,最后构建出一个符合需求的 OkHttpClient 实例。

示例代码
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class OkHttpBuilderExample {
    public static void main(String[] args) {
        // 使用建造者模式构建 OkHttpClient
        OkHttpClient client = new OkHttpClient.Builder()
               .connectTimeout(10, TimeUnit.SECONDS)
               .readTimeout(30, TimeUnit.SECONDS)
               .writeTimeout(30, TimeUnit.SECONDS)
               .build();

        // 创建请求
        Request request = new Request.Builder()
               .url("https://www.example.com")
               .build();

        try {
            // 发起请求
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                System.out.println(response.body().string());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
代码解释
  • OkHttpClient.Builder:这是 OkHttpClient 的建造者类,通过它可以逐步设置 OkHttpClient 的各种属性,比如连接超时时间、读取超时时间等。
  • .build() 方法:调用此方法后,会根据之前设置的属性构建出一个 OkHttpClient 实例。

Retrofit 中的建造者模式

Retrofit 是一个类型安全的 HTTP 客户端,它基于 OkHttp 构建。Retrofit 同样使用建造者模式来配置 Retrofit 实例。

示例代码
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;

interface ApiService {
    @GET("users")
    Call<String> getUsers();
}

public class RetrofitBuilderExample {
    public static void main(String[] args) {
        // 使用建造者模式构建 Retrofit 实例
        Retrofit retrofit = new Retrofit.Builder()
               .baseUrl("https://api.example.com/")
               .addConverterFactory(GsonConverterFactory.create())
               .client(new OkHttpClient())
               .build();

        // 创建 API 服务实例
        ApiService apiService = retrofit.create(ApiService.class);

        // 发起请求
        Call<String> call = apiService.getUsers();
        call.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                if (response.isSuccessful()) {
                    System.out.println(response.body());
                }
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {
                t.printStackTrace();
            }
        });
    }
}
代码解释
  • Retrofit.Builder:这是 Retrofit 的建造者类,通过它可以设置 Retrofit 的各种属性,例如基础 URL、数据转换器工厂、使用的 OkHttpClient 等。
  • .build() 方法:调用此方法后,会根据之前设置的属性构建出一个 Retrofit 实例。

建造者模式在 OkHttp 和 Retrofit 中的优势

  • 可配置性强:可以根据具体需求灵活配置 OkHttpClient 和 Retrofit 的各种属性,而不需要一次性传入所有参数。
  • 代码可读性高:通过链式调用的方式设置属性,使代码更易读和维护。
  • 构建过程清晰:将复杂对象的构建过程分解为多个步骤,使得构建过程更加清晰明了。

感谢观看!!!