为什么Java中的设计模式会让你的代码更优雅?

《Java零基础教学》是一套深入浅出的 Java 编程入门教程。全套教程从Java基础语法开始,适合初学者快速入门,同时也从实例的角度进行了深入浅出的讲解,让初学者能够更好地理解Java编程思想和应用。

本教程内容包括数据类型与运算、流程控制、数组、函数、面向对象基础、字符串、集合、异常处理、IO 流及多线程等 Java 编程基础知识,并提供丰富的实例和练习,帮助读者巩固所学知识。本教程不仅适合初学者学习,也适合已经掌握一定 Java 基础的读者进行查漏补缺。

前言

大家好,我是不熬夜崽崽。作为一名 Java 后端研发,今天想跟大家聊个老生常谈的话题,在我们程序员的世界里,"代码不优雅,开发就会痛苦!",这句看似轻松的话,却道出了软件开发中的一个重要真理:代码的质量直接影响开发效率、代码的可维护性和可扩展性。而如何写出优雅的代码呢?设计模式就是一个能够让你写出高质量代码的重要工具。通过设计模式,我们可以解决常见的编程问题,使得代码结构更加清晰,减少冗余,增加复用性。

当你在面对编程中的一些复杂问题时,你是否曾经希望能够有一套通用的解决方案,能够让你轻松应对?设计模式就是为了解决这种问题而诞生的,它就像是编程世界中的"智慧结晶",给出了经过验证的解决方案。在这篇文章中,我将带你深入了解几种常见的设计模式,并通过具体的代码示例,帮助你理解它们的实际应用。

前言

在我们日常的开发过程中,我们常常会遇到类似的问题:如何处理对象的创建?如何组织不同类之间的关系?如何在对象之间进行交互?而设计模式恰恰提供了这些问题的标准答案。它不仅能提高代码的可读性和可维护性,还能让我们的程序变得更加高效和灵活。

设计模式可以分为三大类:创建型模式、结构型模式和行为型模式。每种模式都专注于解决不同层面的问题,今天我们将逐一介绍,并结合实际的Java代码来展示它们是如何在实际编程中帮助我们提高开发效率的。

设计模式是什么?

设计模式并不是编程语言中的一种新特性,而是一种解决特定问题的通用方法。它通过对问题的抽象和提炼,提供了一些经过实践检验的解决方案。设计模式的出现,帮助程序员在面对类似问题时,能够通过复用已有的设计方案,避免重新发明轮子。

设计模式的目标是减少代码中的冗余部分,增加代码的可重用性和可扩展性。通过设计模式,我们能够让代码变得更加简洁、清晰,避免复杂度的增加。

设计模式大致可以分为三类:

  1. 创建型模式:解决对象创建的问题,主要关注如何创建对象。
  2. 结构型模式:解决类和对象之间的组合与关系,主要关注如何组合不同的类和对象。
  3. 行为型模式:解决对象之间的交互与职责分配,主要关注对象之间的协作。

创建型模式:控制对象的创建过程

创建型设计模式解决了对象创建过程中可能存在的复杂性问题。通过这些模式,我们可以更加优雅地控制对象的创建流程,避免冗余的代码和不必要的复杂性。

单例模式(Singleton Pattern)

单例模式确保一个类只有一个实例,并提供一个全局访问点。在很多场景下,我们只需要一个对象的实例,比如数据库连接池、配置管理器等,这时单例模式就显得尤为重要。它能够确保资源的共享,避免重复创建对象,提高性能。

单例模式实例

java 复制代码
public class Singleton {
    private static Singleton instance;
    
    private Singleton() {
        // 私有构造方法,防止外部创建对象
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

代码解析

  1. Singleton 类的构造方法被声明为私有,防止外部通过 new 关键字创建对象。
  2. getInstance() 方法检查 instance 是否为 null,如果是,则创建一个新的实例;如果已经存在实例,则直接返回该实例,确保了类只有一个实例。
  3. 这种方式确保了延迟加载(lazy initialization),只有在需要时才创建实例,避免了不必要的资源浪费。

工厂模式(Factory Pattern)

工厂模式是用于创建对象的常用设计模式。它通过定义一个接口来创建对象,但由子类决定实例化哪一个类。在实际开发中,我们经常会遇到需要根据不同条件创建不同对象的情况,工厂模式能够帮助我们解决这一问题。

工厂模式实例

java 复制代码
interface Animal {
    void speak();
}

class Dog implements Animal {
    @Override
    public void speak() {
        System.out.println("Woof");
    }
}

class Cat implements Animal {
    @Override
    public void speak() {
        System.out.println("Meow");
    }
}

class AnimalFactory {
    public static Animal createAnimal(String type) {
        if (type.equalsIgnoreCase("dog")) {
            return new Dog();
        } else if (type.equalsIgnoreCase("cat")) {
            return new Cat();
        }
        return null;
    }
}

代码解析

  1. Animal 是一个接口,定义了 speak() 方法,具体的实现类有 DogCat
  2. AnimalFactory 是一个工厂类,根据传入的 type 字符串决定创建 Dog 还是 Cat 对象。
  3. createAnimal() 方法根据输入参数创建相应的动物实例,并返回该实例。工厂模式的核心思想是将对象的创建过程封装到工厂类中,客户端只需调用工厂方法即可。

结构型模式:高效组织类和对象

结构型设计模式关注类与对象之间的关系。通过这些模式,我们能够有效地组织类和对象的结构,简化代码的复杂性,并增强代码的可复用性。

适配器模式(Adapter Pattern)

适配器模式通过提供一个适配器类,将不兼容的接口转换为可用的接口,从而实现不同类之间的兼容性。在实际开发中,适配器模式可以帮助我们避免修改现有代码,而是通过增加适配器类来兼容不同接口。

适配器模式实例demo(实战)

java 复制代码
interface MediaPlayer {
    void play(String fileName);
}

class AudioPlayer implements MediaPlayer {
    @Override
    public void play(String fileName) {
        System.out.println("Playing audio: " + fileName);
    }
}

interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

class VlcPlayer implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing VLC file: " + fileName);
    }

    @Override
    public void playMp4(String fileName) {}
}

class Mp4Player implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {}

    @Override
    public void playMp4(String fileName) {
        System.out.println("Playing MP4 file: " + fileName);
    }
}

class MediaAdapter implements MediaPlayer {
    AdvancedMediaPlayer advancedMusicPlayer;

    public MediaAdapter(String audioType) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMusicPlayer = new VlcPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMusicPlayer = new Mp4Player();
        }
    }

    @Override
    public void play(String fileName) {
        if (fileName.endsWith(".vlc")) {
            advancedMusicPlayer.playVlc(fileName);
        } else if (fileName.endsWith(".mp4")) {
            advancedMusicPlayer.playMp4(fileName);
        }
    }
}

class MediaPlayerTest {
    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();
        audioPlayer.play("audio.mp3");

        MediaAdapter mediaAdapter = new MediaAdapter("vlc");
        mediaAdapter.play("video.vlc");

        mediaAdapter = new MediaAdapter("mp4");
        mediaAdapter.play("video.mp4");
    }
}

代码解析:

  1. AudioPlayer 实现了 MediaPlayer 接口,能够播放常见的音频文件。
  2. AdvancedMediaPlayer 接口和它的实现类 VlcPlayerMp4Player 能够播放更多高级格式的文件。
  3. MediaAdapter 类作为适配器,能够将不同格式的音频文件转化为 MediaPlayer 接口可以播放的格式。
  4. 通过 MediaAdapter,我们实现了 AudioPlayer 类和 VlcPlayerMp4Player 类的兼容,使得 AudioPlayer 能够播放不同格式的音频文件,而不需要修改原来的代码。

执行结果展示:

根据如上案例,本地实际结果运行展示如下,仅供参考:

行为型模式:处理对象之间的交互

行为型设计模式关注对象之间的交互方式和职责分配。通过这些模式,我们可以更加灵活地设计系统中的对象协作,提高系统的灵活性和可扩展性。

观察者模式(Observer Pattern)

观察者模式定义了一个一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。这种模式非常适合事件驱动的场景,例如GUI编程、消息推送等。

观察者模式实例demo(实战)

示例代码

接着,我给大家展示下,结合理论与实战给大家把知识点讲透,案例代码如下:

java 复制代码
import java.util.ArrayList;
import java.util.List;

interface Observer {
    void update(String message);
}

class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " received message: " + message);
    }
}

interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String message;

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }

    public void setMessage(String message) {
        this.message = message;
        notifyObservers();
    }
}

我们再写一个测试函数,给大家演示下:

java 复制代码
/**
 * @Author wf
 * @Date 2025-06-20 09:30
 */
public class OpMainTest {
    public static void main(String[] args) {
        // 创建主题对象
        ConcreteSubject subject = new ConcreteSubject();

        // 创建观察者对象
        ConcreteObserver observer1 = new ConcreteObserver("Observer 1");
        ConcreteObserver observer2 = new ConcreteObserver("Observer 2");

        // 注册观察者
        subject.addObserver(observer1);
        subject.addObserver(observer2);

        // 设置消息,通知观察者
        subject.setMessage("Hello, Observers!");

        // 移除一个观察者
        subject.removeObserver(observer2);

        // 再次设置消息,通知剩余的观察者
        subject.setMessage("Hello, Observer 1!");
    }
}
结果运行展示

根据如上案例,本地实际结果运行展示如下,仅供参考:

代码解析

根据如上我所给出的案例demo,着重进行代码解析,希望能够辅助大家理解。

如上这段示例代码,我基本是实现了观察者模式(Observer Pattern)。该模式用于处理一个对象(主题)状态变化时,如何通知所有依赖于它的对象(观察者)。以下是这段代码的详细文字解析:

观察者模式的核心思想:

观察者模式是一种一对多 的设计模式,主要用于解决对象之间的耦合问题。当一个对象的状态发生变化时,所有依赖于它的对象都会被通知并自动更新。主题对象和观察者对象之间通过接口进行交互,从而避免了它们之间的直接耦合。

核心组件:

  1. Observer(观察者)

    • 观察者是一个接口,定义了当主题状态改变时如何响应更新。每个具体的观察者类需要实现这个接口,并定义自己的更新行为。
    • 观察者通过一个 update 方法接收并处理来自主题的消息。
  2. ConcreteObserver(具体观察者)

    • 具体观察者实现了 Observer 接口,并定义了当主题状态发生变化时,它如何响应变化。
    • 每个观察者对象维护自己的状态(例如名称),并通过更新方法(update)处理主题的消息。通常,它会在控制台打印出接收到的消息或做出相应的操作。
  3. Subject(主题)

    • 主题是被观察的对象,维护了一个观察者列表。当主题状态发生变化时,主题通过 notifyObservers 方法通知所有注册的观察者。
    • 主题提供了方法来添加和移除观察者,使得观察者可以动态地注册和注销。
  4. ConcreteSubject(具体主题)

    • 具体主题实现了 Subject 接口,管理观察者列表,并负责通知观察者。
    • 主题的状态是变化的,通常表现为一些数据(如消息),当状态变化时,主题会调用 notifyObservers 方法通知所有的观察者,更新它们的状态。
    • 主题通过 setMessage 方法更新状态,并在更新后调用 notifyObservers 来通知所有观察者。

工作流程:

  1. 注册观察者 :观察者通过 addObserver 方法注册到主题中。多个观察者可以同时注册到同一个主题。
  2. 主题状态变化 :当主题的状态发生变化时(例如消息被更新),主题调用 setMessage 方法设置新的状态,并触发 notifyObservers 方法。
  3. 通知观察者notifyObservers 方法会遍历所有注册的观察者,并调用每个观察者的 update 方法,将主题的新状态传递给观察者。
  4. 观察者处理更新 :每个观察者会在 update 方法中接收到新的消息,并做出响应(通常是更新显示或处理其他业务逻辑)。

优势:

  • 解耦:观察者模式的核心优势是解耦。主题和观察者之间没有直接的依赖关系,主题只知道如何通知观察者,而不知道观察者的具体实现。观察者的实现也不会影响主题的运行。
  • 动态订阅:观察者可以在运行时动态地注册或注销,不需要在代码编写时就确定固定的观察者数量。
  • 一对多通知:主题可以同时通知多个观察者,当主题状态变化时,所有的观察者都能收到通知并做出相应。

应用场景:

观察者模式常见的应用场景包括:

  • 事件处理系统:例如按钮点击、鼠标移动等事件通知。
  • 发布-订阅模式:在新闻订阅、股票信息更新等场景中,用户(观察者)可以订阅感兴趣的内容,当内容更新时,所有订阅用户都会收到通知。
  • GUI界面:图形用户界面中的多个组件(按钮、标签等)可能会对用户的操作作出反应,通过观察者模式可以实现响应式界面的设计。

总结

设计模式并不高深,它们通过提供标准化的解决方案,帮助我们减少代码的复杂性,提高代码的可维护性、可扩展性和复用性。今天,我们介绍了几种常见的设计模式,并通过具体的Java代码示例帮助你理解它们的应用。

设计模式不仅仅是理论,它是我们在实际开发中不可或缺的工具。掌握了设计模式,你将能够写出更加简洁、优雅的代码,提升开发效率,减少错误,提升代码的可读性和可维护性。

最后,大家如果觉得看了本文有帮助的话,麻烦给不熬夜崽崽点个三连(点赞、收藏、关注)支持一下哈,大家的支持就是我写作的无限动力。

相关推荐
晴空月明2 分钟前
线程安全集合选择深度解析
java
是紫焅呢2 分钟前
I排序算法.go
开发语言·后端·算法·golang·排序算法·学习方法·visual studio code
mxpan9 分钟前
C++ 单例模式一种实现方式
c++·设计模式
lovebugs11 分钟前
Java线上死锁问题实战:从定位到解决的全链路指南
java·后端·面试
飞飞帅傅20 分钟前
go语言位运算
开发语言·后端·golang
Rancemy29 分钟前
Redis03
java·服务器·redis·spring
only-lucky1 小时前
C++设计模式
java·c++·设计模式
黄豆匿zlib1 小时前
Python中布尔值在函数中的巧妙运用
java·服务器·python
峥嵘life1 小时前
Android Java语言转Kotlin语言学习指导实用攻略
android·java·kotlin