Java设计模式简单入门

Java设计模式简单入门

1. 设计模式概述

1.1 什么是设计模式?

设计模式(Design Pattern)是面向对象编程中解决常见问题的经典解决方案。它们是前人经验的总结,代表了最佳实践。设计模式并不是具体的代码,而是描述在各种不同情况下如何解决问题的方案。

设计模式有以下特点:

  • 是解决特定问题的经验总结
  • 是被广泛验证过的解决方案
  • 是可以被反复使用的模板
  • 提高代码的可重用性、可读性和可靠性

1.2 设计模式的历史

设计模式的概念最初由建筑师克里斯托弗·亚历山大提出,后来被Gang of Four(GoF)引入软件开发领域。1994年,Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著的《设计模式:可复用面向对象软件的基础》一书,正式确立了23种经典设计模式。

1.3 设计模式的重要性

  • 提高代码质量:使代码更清晰、更易于理解
  • 增强可维护性:更容易修改和扩展
  • 促进团队协作:提供通用术语和模板
  • 减少开发时间:使用成熟方案快速解决问题
  • 降低风险:采用经过验证的解决方案

2. 面向对象设计原则

在学习设计模式之前,需要了解一些基本的设计原则:

2.1 SOLID原则

  1. 单一职责原则(SRP):一个类应该只有一个引起它变化的原因
  2. 开闭原则(OCP):对扩展开放,对修改关闭
  3. 里氏替换原则(LSP):子类必须能够替换其基类
  4. 接口隔离原则(ISP):客户端不应该依赖它们不需要的接口
  5. 依赖倒置原则(DIP):高层模块不应该依赖低层模块,两者都应该依赖抽象

2.2 其他重要原则

  • 迪米特法则(最少知识原则):一个对象应该对其他对象保持最少的了解
  • 合成复用原则:优先使用组合而非继承

3. 设计模式分类

根据GoF的分类,设计模式分为三大类:

3.1 创建型模式(Creational Patterns)

  • 单例模式(Singleton Pattern)
  • 工厂方法模式(Factory Method Pattern)
  • 抽象工厂模式(Abstract Factory Pattern)
  • 建造者模式(Builder Pattern)
  • 原型模式(Prototype Pattern)

3.2 结构型模式(Structural Patterns)

  • 适配器模式(Adapter Pattern)
  • 装饰器模式(Decorator Pattern)
  • 代理模式(Proxy Pattern)
  • 外观模式(Facade Pattern)
  • 桥接模式(Bridge Pattern)
  • 组合模式(Composite Pattern)
  • 享元模式(Flyweight Pattern)

3.3 行为型模式(Behavioral Patterns)

  • 策略模式(Strategy Pattern)
  • 模板方法模式(Template Method Pattern)
  • 观察者模式(Observer Pattern)
  • 迭代器模式(Iterator Pattern)
  • 责任链模式(Chain of Responsibility Pattern)
  • 命令模式(Command Pattern)
  • 备忘录模式(Memento Pattern)
  • 状态模式(State Pattern)
  • 访问者模式(Visitor Pattern)
  • 中介者模式(Mediator Pattern)
  • 解释器模式(Interpreter Pattern)

4. 创建型模式详解

4.1 单例模式(Singleton Pattern)

4.1.1 模式意图

确保一个类只有一个实例,并提供一个全局访问点。

4.1.2 应用场景
  • 配置文件管理器
  • 日志记录器
  • 数据库连接池
  • 线程池
4.1.3 实现方式

饿汉式(线程安全):

java 复制代码
public class EagerSingleton {
    private static final EagerSingleton INSTANCE = new EagerSingleton();
    
    private EagerSingleton() {}
    
    public static EagerSingleton getInstance() {
        return INSTANCE;
    }
}

懒汉式(线程不安全):

java 复制代码
public class LazySingleton {
    private static LazySingleton instance;
    
    private LazySingleton() {}
    
    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

双重检查锁定(线程安全):

java 复制代码
public class DoubleCheckLockingSingleton {
    private static volatile DoubleCheckLockingSingleton instance;
    
    private DoubleCheckLockingSingleton() {}
    
    public static DoubleCheckLockingSingleton getInstance() {
        if (instance == null) {
            synchronized (DoubleCheckLockingSingleton.class) {
                if (instance == null) {
                    instance = new DoubleCheckLockingSingleton();
                }
            }
        }
        return instance;
    }
}

静态内部类(推荐):

java 复制代码
public class StaticInnerClassSingleton {
    private StaticInnerClassSingleton() {}
    
    private static class SingletonHolder {
        private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
    }
    
    public static StaticInnerClassSingleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

枚举(最安全):

java 复制代码
public enum EnumSingleton {
    INSTANCE;
    
    public void doSomething() {
        System.out.println("Do something");
    }
}
4.1.4 优缺点

优点:

  • 内存中只有一个实例,节约内存
  • 全局访问点,便于控制

缺点:

  • 扩展困难
  • 违反单一职责原则
  • 测试困难

4.2 工厂方法模式(Factory Method Pattern)

4.2.1 模式意图

定义一个用于创建对象的接口,让子类决定实例化哪一个类。

4.2.2 应用场景
  • 日志记录器选择
  • 数据库连接器
  • UI控件创建
4.2.3 实现
java 复制代码
// 产品接口
interface Product {
    void use();
}

// 具体产品
class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("Using product A");
    }
}

class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("Using product B");
    }
}

// 工厂接口
interface Factory {
    Product createProduct();
}

// 具体工厂
class ConcreteFactoryA implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

class ConcreteFactoryB implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Factory factoryA = new ConcreteFactoryA();
        Product productA = factoryA.createProduct();
        productA.use(); // 输出: Using product A
        
        Factory factoryB = new ConcreteFactoryB();
        Product productB = factoryB.createProduct();
        productB.use(); // 输出: Using product B
    }
}
4.2.4 优缺点

优点:

  • 符合开闭原则
  • 解耦合
  • 支持依赖注入

缺点:

  • 类数量增加
  • 复杂度提高

4.3 抽象工厂模式(Abstract Factory Pattern)

4.3.1 模式意图

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

4.3.2 应用场景
  • 跨平台UI界面
  • 数据库访问层
  • 游戏开发中的主题包
4.3.3 实现
java 复制代码
// 抽象产品A
interface Button {
    void paint();
}

// 抽象产品B
interface Checkbox {
    void paint();
}

// Windows风格的具体产品
class WindowsButton implements Button {
    @Override
    public void paint() {
        System.out.println("Windows button painted");
    }
}

class WindowsCheckbox implements Checkbox {
    @Override
    public void paint() {
        System.out.println("Windows checkbox painted");
    }
}

// MacOS风格的具体产品
class MacButton implements Button {
    @Override
    public void paint() {
        System.out.println("Mac button painted");
    }
}

class MacCheckbox implements Checkbox {
    @Override
    public void paint() {
        System.out.println("Mac checkbox painted");
    }
}

// 抽象工厂
interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

// 具体工厂
class WindowsFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }
    
    @Override
    public Checkbox createCheckbox() {
        return new WindowsCheckbox();
    }
}

class MacFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }
    
    @Override
    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}

// 客户端
public class Application {
    private Button button;
    private Checkbox checkbox;
    
    public Application(GUIFactory factory) {
        this.button = factory.createButton();
        this.checkbox = factory.createCheckbox();
    }
    
    public void paint() {
        button.paint();
        checkbox.paint();
    }
    
    public static void main(String[] args) {
        String osName = System.getProperty("os.name").toLowerCase();
        GUIFactory factory;
        
        if (osName.contains("win")) {
            factory = new WindowsFactory();
        } else {
            factory = new MacFactory();
        }
        
        Application app = new Application(factory);
        app.paint();
    }
}

4.4 建造者模式(Builder Pattern)

4.4.1 模式意图

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

4.4.2 应用场景
  • SQL查询构造器
  • HTTP请求构造器
  • 复杂对象的创建
4.4.3 实现
java 复制代码
// 产品类
class Meal {
    private String food;
    private String drink;
    private String dessert;
    
    private Meal(Builder builder) {
        this.food = builder.food;
        this.drink = builder.drink;
        this.dessert = builder.dessert;
    }
    
    public static class Builder {
        private String food;
        private String drink;
        private String dessert;
        
        public Builder setFood(String food) {
            this.food = food;
            return this;
        }
        
        public Builder setDrink(String drink) {
            this.drink = drink;
            return this;
        }
        
        public Builder setDessert(String dessert) {
            this.dessert = dessert;
            return this;
        }
        
        public Meal build() {
            return new Meal(this);
        }
    }
    
    @Override
    public String toString() {
        return "Meal{" +
                "food='" + food + '\'' +
                ", drink='" + drink + '\'' +
                ", dessert='" + dessert + '\'' +
                '}';
    }
}

// 客户端
public class BuilderDemo {
    public static void main(String[] args) {
        Meal meal = new Meal.Builder()
                .setFood("Burger")
                .setDrink("Coke")
                .setDessert("Ice Cream")
                .build();
        
        System.out.println(meal);
    }
}

4.5 原型模式(Prototype Pattern)

4.5.1 模式意图

用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

4.5.2 应用场景
  • 对象克隆
  • 深拷贝和浅拷贝操作
4.5.3 实现
java 复制代码
interface Prototype {
    Prototype clone();
}

class ConcretePrototype implements Prototype, Cloneable {
    private String name;
    private int age;
    
    public ConcretePrototype(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public ConcretePrototype clone() {
        try {
            return (ConcretePrototype) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
    
    // Getter和Setter方法
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    
    @Override
    public String toString() {
        return "ConcretePrototype{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

5. 结构型模式详解

5.1 适配器模式(Adapter Pattern)

5.1.1 模式意图

将一个类的接口转换成客户希望的另一个接口。

5.1.2 应用场景
  • 第三方库集成
  • 旧系统接口兼容
  • 不同数据格式转换
5.1.3 实现
java 复制代码
// 目标接口
interface MediaPlayer {
    void play(String audioType, String fileName);
}

// 被适配的类
class AdvancedMediaPlayer {
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }
    
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file. Name: " + 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 audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMusicPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMusicPlayer.playMp4(fileName);
        }
    }
}

class VlcPlayer extends AdvancedMediaPlayer {
    // 实现播放VLC的方法
}

class Mp4Player extends AdvancedMediaPlayer {
    // 实现播放MP4的方法
}

// 客户端
class AudioPlayer implements MediaPlayer {
    MediaAdapter mediaAdapter;
    
    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("mp3")) {
            System.out.println("Playing mp3 file. Name: " + fileName);
        } else if (audioType.equalsIgnoreCase("vlc") || 
                   audioType.equalsIgnoreCase("mp4")) {
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        } else {
            System.out.println("Invalid media. " + 
                              audioType + " format not supported");
        }
    }
}

5.2 装饰器模式(Decorator Pattern)

5.2.1 模式意图

动态地给一个对象添加一些额外的职责。

5.2.2 应用场景
  • Java IO流
  • Servlet过滤器
  • 缓存装饰
5.2.3 实现
java 复制代码
// 抽象组件
interface Coffee {
    String getDescription();
    double getCost();
}

// 具体组件
class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "Simple coffee";
    }
    
    @Override
    public double getCost() {
        return 1.0;
    }
}

// 抽象装饰器
abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }
    
    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription();
    }
    
    @Override
    public double getCost() {
        return decoratedCoffee.getCost();
    }
}

// 具体装饰器
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return super.getDescription() + ", milk";
    }
    
    @Override
    public double getCost() {
        return super.getCost() + 0.5;
    }
}

class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return super.getDescription() + ", sugar";
    }
    
    @Override
    public double getCost() {
        return super.getCost() + 0.2;
    }
}

// 客户端测试
public class DecoratorDemo {
    public static void main(String[] args) {
        Coffee coffee = new SimpleCoffee();
        System.out.println(coffee.getDescription() + ": $" + coffee.getCost());
        
        Coffee milkCoffee = new MilkDecorator(new SimpleCoffee());
        System.out.println(milkCoffee.getDescription() + ": $" + milkCoffee.getCost());
        
        Coffee sugarMilkCoffee = new SugarDecorator(new MilkDecorator(new SimpleCoffee()));
        System.out.println(sugarMilkCoffee.getDescription() + ": $" + sugarMilkCoffee.getCost());
    }
}

5.3 代理模式(Proxy Pattern)

5.3.1 模式意图

为其他对象提供一种代理以控制对这个对象的访问。

5.3.2 应用场景
  • 远程代理
  • 虚拟代理
  • 保护代理
  • 智能引用
5.3.3 实现
java 复制代码
// 主题接口
interface Image {
    void display();
}

// 真实主题
class RealImage implements Image {
    private String fileName;
    
    public RealImage(String fileName) {
        this.fileName = fileName;
        loadFromDisk();
    }
    
    private void loadFromDisk() {
        System.out.println("Loading " + fileName);
    }
    
    @Override
    public void display() {
        System.out.println("Displaying " + fileName);
    }
}

// 代理
class ProxyImage implements Image {
    private RealImage realImage;
    private String fileName;
    
    public ProxyImage(String fileName) {
        this.fileName = fileName;
    }
    
    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(fileName);
        }
        realImage.display();
    }
}

// 客户端
public class ProxyPatternDemo {
    public static void main(String[] args) {
        Image image = new ProxyImage("test.jpg");
        
        // 图像将从磁盘加载
        image.display();
        System.out.println("");
        
        // 图像不需要从磁盘加载
        image.display();
    }
}

5.4 外观模式(Facade Pattern)

5.4.1 模式意图

为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

5.4.2 应用场景
  • 简化复杂系统的接口
  • 分层系统架构
  • 框架设计
5.4.3 实现
java 复制代码
// 子系统类
class CPU {
    public void freeze() { System.out.println("CPU: freeze"); }
    public void jump(long position) { System.out.println("CPU: jump to " + position); }
    public void execute() { System.out.println("CPU: execute"); }
}

class Memory {
    public void load(long position, byte[] data) {
        System.out.println("Memory: load data at " + position);
    }
}

class HardDrive {
    public byte[] read(long lba, int size) {
        System.out.println("HardDrive: read " + size + " bytes from LBA " + lba);
        return new byte[size];
    }
}

// 外观类
class ComputerFacade {
    private CPU cpu;
    private Memory memory;
    private HardDrive hardDrive;
    
    public ComputerFacade() {
        this.cpu = new CPU();
        this.memory = new Memory();
        this.hardDrive = new HardDrive();
    }
    
    public void start() {
        cpu.freeze();
        memory.load(0, hardDrive.read(0, 1024));
        cpu.jump(0);
        cpu.execute();
    }
}

// 客户端
public class FacadeDemo {
    public static void main(String[] args) {
        ComputerFacade computer = new ComputerFacade();
        computer.start();
    }
}

6. 行为型模式详解

6.1 策略模式(Strategy Pattern)

6.1.1 模式意图

定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。

6.1.2 应用场景
  • 排序算法选择
  • 支付方式选择
  • 计算策略
6.1.3 实现
java 复制代码
// 策略接口
interface Strategy {
    int doOperation(int num1, int num2);
}

// 具体策略
class OperationAdd implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 + num2;
    }
}

class OperationSubtract implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 - num2;
    }
}

class OperationMultiply implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 * num2;
    }
}

// 上下文
class Context {
    private Strategy strategy;
    
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public int executeStrategy(int num1, int num2) {
        return strategy.doOperation(num1, num2);
    }
}

// 客户端
public class StrategyPatternDemo {
    public static void main(String[] args) {
        Context context = new Context(new OperationAdd());
        System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
        
        context = new Context(new OperationSubtract());
        System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
        
        context = new Context(new OperationMultiply());
        System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
    }
}

6.2 观察者模式(Observer Pattern)

6.2.1 模式意图

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

6.2.2 应用场景
  • 事件驱动系统
  • MVC架构中的模型-视图关系
  • 发布-订阅系统
6.2.3 实现
复制代码
import java.util.ArrayList;
import java.util.List;

// 观察者接口
interface Observer {
    void update(String message);
}

// 主题接口
interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers(String message);
}

// 具体主题
class NewsAgency implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String news;
    
    @Override
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    @Override
    public void detach(Observer observer) {
        observers.remove(observer);
    }
    
    @Override
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
    
    public void setNews(String news) {
        this.news = news;
        notifyObservers(news);
    }
}

// 具体观察者
class NewsChannel implements Observer {
    private String news;
    
    @Override
    public void update(String message) {
        this.news = message;
        System.out.println("NewsChannel received news: " + news);
    }
}

// 客户端
public class ObserverPatternDemo {
    public static void main(String[] args) {
        NewsAgency newsAgency = new NewsAgency();
        NewsChannel channel1 = new NewsChannel();
        NewsChannel channel2 = new NewsChannel();
        
        newsAgency.attach(channel1);
        newsAgency.attach(channel2);
        
        newsAgency.setNews("Breaking News: Java 17 Released!");
    }
}

6.3 模板方法模式(Template Method Pattern)

6.3.1 模式意图

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。

6.3.2 应用场景
  • 框架设计
  • 算法框架
  • 业务流程
6.3.3 实现
java 复制代码
abstract class Game {
    // 模板方法
    public final void play() {
        initialize();
        startPlay();
        endPlay();
    }
    
    abstract void initialize();
    abstract void startPlay();
    abstract void endPlay();
}

class Cricket extends Game {
    @Override
    void initialize() {
        System.out.println("Cricket Game Initialized! Start playing.");
    }
    
    @Override
    void startPlay() {
        System.out.println("Cricket Game Started. Enjoy the game!");
    }
    
    @Override
    void endPlay() {
        System.out.println("Cricket Game Finished!");
    }
}

class Football extends Game {
    @Override
    void initialize() {
        System.out.println("Football Game Initialized! Start playing.");
    }
    
    @Override
    void startPlay() {
        System.out.println("Football Game Started. Enjoy the game!");
    }
    
    @Override
    void endPlay() {
        System.out.println("Football Game Finished!");
    }
}

// 客户端
public class TemplateMethodPatternDemo {
    public static void main(String[] args) {
        Game game = new Cricket();
        game.play();
        System.out.println();
        
        game = new Football();
        game.play();
    }
}

6.4 命令模式(Command Pattern)

6.4.1 模式意图

将一个请求封装为一个对象,从而使您可以用不同的请求对客户进行参数化。

6.4.2 应用场景
  • 撤销/重做功能
  • 事务处理
  • 队列请求
6.4.3 实现
java 复制代码
// 命令接口
interface Command {
    void execute();
}

// 接收者
class Light {
    public void turnOn() {
        System.out.println("Light is turned on");
    }
    
    public void turnOff() {
        System.out.println("Light is turned off");
    }
}

// 具体命令
class TurnOnLightCommand implements Command {
    private Light light;
    
    public TurnOnLightCommand(Light light) {
        this.light = light;
    }
    
    @Override
    public void execute() {
        light.turnOn();
    }
}

class TurnOffLightCommand implements Command {
    private Light light;
    
    public TurnOffLightCommand(Light light) {
        this.light = light;
    }
    
    @Override
    public void execute() {
        light.turnOff();
    }
}

// 调用者
class Switch {
    private Command command;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void executeCommand() {
        command.execute();
    }
}

// 客户端
public class CommandPatternDemo {
    public static void main(String[] args) {
        Light livingRoomLight = new Light();
        
        Command lightOn = new TurnOnLightCommand(livingRoomLight);
        Command lightOff = new TurnOffLightCommand(livingRoomLight);
        
        Switch lightSwitch = new Switch();
        
        lightSwitch.setCommand(lightOn);
        lightSwitch.executeCommand();
        
        lightSwitch.setCommand(lightOff);
        lightSwitch.executeCommand();
    }
}

7. 设计模式进阶应用

7.1 模式组合使用

在实际开发中,经常需要组合多个设计模式来解决复杂问题。例如:

  • MVC架构中结合了观察者模式、策略模式、组合模式等
  • Spring框架中大量使用了工厂模式、代理模式、模板方法模式等
  • MyBatis框架中使用了建造者模式、工厂模式、代理模式等

7.2 反模式识别

虽然设计模式有很多优点,但也要注意避免滥用:

  1. 过度设计:为了使用模式而使用模式
  2. 模式误用:在不合适的地方使用某种模式
  3. 复杂性增加:引入不必要的抽象层次

7.3 性能考虑

某些设计模式可能会带来性能开销:

  • 代理模式可能增加调用开销
  • 装饰器模式可能导致对象嵌套过深
  • 观察者模式可能导致内存泄漏

8. 实战案例分析

8.1 日志系统设计

使用单例模式、策略模式、装饰器模式构建日志系统:

java 复制代码
// 日志接口
interface Logger {
    void log(String message);
}

// 文件日志实现
class FileLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("Logging to file: " + message);
    }
}

// 控制台日志实现
class ConsoleLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("Logging to console: " + message);
    }
}

// 日志策略
class LoggerFactory {
    public static Logger getLogger(String type) {
        if ("file".equalsIgnoreCase(type)) {
            return new FileLogger();
        } else if ("console".equalsIgnoreCase(type)) {
            return new ConsoleLogger();
        }
        return new ConsoleLogger();
    }
}

// 日志装饰器
class TimestampLogger implements Logger {
    private Logger logger;
    
    public TimestampLogger(Logger logger) {
        this.logger = logger;
    }
    
    @Override
    public void log(String message) {
        logger.log("[" + System.currentTimeMillis() + "] " + message);
    }
}

// 单例日志管理器
class LogManager {
    private static volatile LogManager instance;
    private Logger logger;
    
    private LogManager() {
        // 默认使用带时间戳的控制台日志
        this.logger = new TimestampLogger(new ConsoleLogger());
    }
    
    public static LogManager getInstance() {
        if (instance == null) {
            synchronized (LogManager.class) {
                if (instance == null) {
                    instance = new LogManager();
                }
            }
        }
        return instance;
    }
    
    public void log(String message) {
        logger.log(message);
    }
    
    public void setLogger(Logger logger) {
        this.logger = new TimestampLogger(logger);
    }
}

8.2 缓存系统设计

使用单例模式、策略模式、观察者模式构建缓存系统:

java 复制代码
import java.util.HashMap;
import java.util.Map;

// 缓存接口
interface Cache<K, V> {
    V get(K key);
    void put(K key, V value);
    void remove(K key);
    void clear();
}

// LRU缓存实现
class LRUCache<K, V> implements Cache<K, V> {
    private Map<K, V> cache;
    private int capacity;
    
    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.cache = new HashMap<>();
    }
    
    @Override
    public V get(K key) {
        return cache.get(key);
    }
    
    @Override
    public void put(K key, V value) {
        if (cache.size() >= capacity) {
            // 简化的LRU实现,实际应使用LinkedHashMap
            K firstKey = cache.keySet().iterator().next();
            cache.remove(firstKey);
        }
        cache.put(key, value);
    }
    
    @Override
    public void remove(K key) {
        cache.remove(key);
    }
    
    @Override
    public void clear() {
        cache.clear();
    }
}

// 缓存工厂
class CacheFactory {
    public static <K, V> Cache<K, V> createCache(String type, int capacity) {
        if ("lru".equalsIgnoreCase(type)) {
            return new LRUCache<>(capacity);
        }
        return new LRUCache<>(capacity);
    }
}

// 缓存管理器
class CacheManager<K, V> {
    private static volatile CacheManager instance;
    private Cache<K, V> cache;
    
    private CacheManager() {
        this.cache = CacheFactory.createCache("lru", 100);
    }
    
    public static <K, V> CacheManager<K, V> getInstance() {
        if (instance == null) {
            synchronized (CacheManager.class) {
                if (instance == null) {
                    instance = new CacheManager<>();
                }
            }
        }
        return instance;
    }
    
    public V get(K key) {
        return cache.get(key);
    }
    
    public void put(K key, V value) {
        cache.put(key, value);
    }
    
    public void remove(K key) {
        cache.remove(key);
    }
}

9. 学习路径建议

9.1 入门阶段

  1. 理解面向对象基本原则
  2. 掌握常用设计模式的基本概念
  3. 熟悉每种模式的典型应用场景
  4. 阅读经典设计模式书籍

9.2 进阶阶段

  1. 深入理解设计模式的本质
  2. 学习模式间的关联和区别
  3. 阅读开源项目的源码
  4. 在项目中尝试应用设计模式

9.3 精通阶段

  1. 能够灵活组合多种设计模式
  2. 能够识别和避免反模式
  3. 能够根据具体场景选择合适的模式
  4. 能够设计出符合设计原则的架构

10. 总结

设计模式是软件开发中宝贵的经验总结,掌握它们有助于:

  • 提高代码质量
  • 增强代码可维护性
  • 促进团队协作
  • 加速问题解决

但要注意,设计模式不是银弹,应在合适的地方使用合适的模式。随着经验的积累,你会更好地理解和应用这些模式。

记住:设计模式的目的是解决问题,而不是为了使用模式而使用模式。始终以解决实际问题为导向,选择最适合的方案。

11. 代码整洁实践指南

在应用设计模式的同时,还需要遵循代码整洁的最佳实践。整洁的代码不仅易于理解和维护,还能减少错误的发生。以下是几个重要的代码整洁实践:

11.1 方法长度控制

方法体不要太长,最好不要超过80行 。过长的方法难以理解,增加了维护难度。如果一个方法超过80行,应该考虑将其拆分为多个更小的方法。在IDEA中,可以使用快捷键 Ctrl+Alt+M 来快速提取方法。

java 复制代码
// 不好的例子:方法过长
public void processUserData() {
    // 100行代码...
}

// 好的例子:将功能拆分到多个方法中
public void processUserData() {
    validateInput();
    transformData();
    saveToDatabase();
    sendNotification();
}

private void validateInput() {
    // 输入验证逻辑
}

private void transformData() {
    // 数据转换逻辑
}

private void saveToDatabase() {
    // 数据库保存逻辑
}

private void sendNotification() {
    // 通知发送逻辑
}

11.2 使用提前返回避免深层嵌套

使用if-return代替嵌套if语句。深层嵌套的if语句会降低代码的可读性,应该优先使用提前返回(guard clauses)来减少嵌套层级。

java 复制代码
// 不好的例子:深层嵌套
public void processUser(User user) {
    if (user != null) {
        if (user.isActive()) {
            if (user.hasPermission()) {
                // 主要逻辑
                System.out.println("Processing user: " + user.getName());
            } else {
                System.out.println("User doesn't have permission");
            }
        } else {
            System.out.println("User is not active");
        }
    } else {
        System.out.println("User is null");
    }
}

// 好的例子:使用提前返回
public void processUser(User user) {
    if (user == null) {
        System.out.println("User is null");
        return;
    }
    
    if (!user.isActive()) {
        System.out.println("User is not active");
        return;
    }
    
    if (!user.hasPermission()) {
        System.out.println("User doesn't have permission");
        return;
    }
    
    // 主要逻辑 - 代码更清晰
    System.out.println("Processing user: " + user.getName());
}

11.3 复杂条件抽象

如果if条件过于复杂,应该抽象为方法或变量。复杂的条件判断会影响代码的可读性,应该将其提取为有意义的变量或方法。

``java

// 不好的例子:复杂条件判断

if (user.getAge() >= 18 && user.hasValidId() && user.getAccountBalance() > 1000 && !user.isBlacklisted()) {

// 处理逻辑

}

// 好的例子:将复杂条件抽象为变量

boolean isEligibleForService = user.getAge() >= 18 &&

user.hasValidId() &&

user.getAccountBalance() > 1000 &&

!user.isBlacklisted();

if (isEligibleForService) {

// 处理逻辑

}

// 或者抽象为方法

private boolean isEligibleForService(User user) {

return user.getAge() >= 18 &&

user.hasValidId() &&

user.getAccountBalance() > 1000 &&

!user.isBlacklisted();

}

复制代码
### 11.4 空指针检查

**多使用空指针判断**。空指针异常是程序中最常见的运行时错误之一,应该在适当的位置进行空指针检查:

// 需要进行空指针检查的场景:

// 1. 方法入口参数检查

public void processUser(User user) {

if (user == null) {

throw new IllegalArgumentException("User cannot be null");

}

// 处理逻辑

}

// 2. 接收方法返回值时检查

UserService userService = getUserService();

if (userService != null) {

User user = userService.getCurrentUser();

if (user != null) {

// 使用user

}

}

// 3. 对象级联调用时检查

// 不安全的调用

String department = user.getProfile().getDepartment().getName();

// 安全的调用

if (user != null && user.getProfile() != null &&

user.getProfile().getDepartment() != null) {

String department = user.getProfile().getDepartment().getName();

}

// 或者使用Optional(Java 8+)

Optional.ofNullable(user)

.map(User::getProfile)

.map(Profile::getDepartment)

.map(Department::getName)

.orElse("Unknown");

复制代码
### 11.5 字符串比较

**判断字符串是否相等时,使用equals方法**。使用 == 比较字符串可能会因为字符串常量池的问题导致错误的结果。

```java
// 错误的做法
if (status == "ACTIVE") {
    // 逻辑
}

// 正确的做法
if ("ACTIVE".equals(status)) {
    // 逻辑 - 推荐这种方式,可以避免空指针异常
}

// 或者
if (status != null && status.equals("ACTIVE")) {
    // 逻辑
}

// 使用equalsIgnoreCase忽略大小写比较
if ("ACTIVE".equalsIgnoreCase(status)) {
    // 逻辑
}

11.6 策略模式替代大量if-else

如果有大量if-else出现,考虑使用策略模式。当出现多个条件分支时,策略模式可以提高代码的可扩展性和可维护性。

java 复制代码
// 不好的例子:大量if-else
public class PaymentProcessor {
    public void processPayment(String paymentType, double amount) {
        if ("CREDIT_CARD".equals(paymentType)) {
            // 信用卡支付逻辑
        } else if ("DEBIT_CARD".equals(paymentType)) {
            // 借记卡支付逻辑
        } else if ("PAYPAL".equals(paymentType)) {
            // PayPal支付逻辑
        } else if ("BANK_TRANSFER".equals(paymentType)) {
            // 银行转账逻辑
        }
        // 每次新增支付方式都要修改这个方法
    }
}

// 好的例子:使用策略模式
interface PaymentStrategy {
    void processPayment(double amount);
}

class CreditCardPayment implements PaymentStrategy {
    @Override
    public void processPayment(double amount) {
        // 信用卡支付逻辑
        System.out.println("Processing credit card payment: " + amount);
    }
}

class DebitCardPayment implements PaymentStrategy {
    @Override
    public void processPayment(double amount) {
        // 借记卡支付逻辑
        System.out.println("Processing debit card payment: " + amount);
    }
}

class PayPalPayment implements PaymentStrategy {
    @Override
    public void processPayment(double amount) {
        // PayPal支付逻辑
        System.out.println("Processing PayPal payment: " + amount);
    }
}

class PaymentContext {
    private PaymentStrategy strategy;
    
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void executePayment(double amount) {
        strategy.processPayment(amount);
    }
}

11.7 枚举类型使用

如果有大量类型判断,将类型定义为枚举,便于维护和扩展。

java 复制代码
// 不好的例子:使用字符串常量
public class OrderProcessor {
    public void processOrder(String orderType) {
        if ("NORMAL".equals(orderType)) {
            // 普通订单处理
        } else if ("PREMIUM".equals(orderType)) {
            // 高级订单处理
        } else if ("VIP".equals(orderType)) {
            // VIP订单处理
        }
    }
}

// 好的例子:使用枚举
public enum OrderType {
    NORMAL("普通订单"),
    PREMIUM("高级订单"), 
    VIP("VIP订单");
    
    private final String description;
    
    OrderType(String description) {
        this.description = description;
    }
    
    public String getDescription() {
        return description;
    }
}

public class OrderProcessor {
    public void processOrder(OrderType orderType) {
        switch (orderType) {
            case NORMAL:
                // 普通订单处理
                break;
            case PREMIUM:
                // 高级订单处理
                break;
            case VIP:
                // VIP订单处理
                break;
        }
    }
}

11.8 业务逻辑与数据查询分离

尽量用业务代码组装结果,代替多表联合查询。虽然多表联合查询在某些情况下性能更好,但过度依赖复杂的SQL查询会使业务逻辑难以理解和维护。

java 复制代码
// 不好的例子:复杂的多表联合查询
// SQL: SELECT u.name, p.title, c.name FROM users u JOIN posts p ON u.id = p.user_id JOIN categories c ON p.category_id = c.id

// 好的例子:在业务代码中组装数据
@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private PostRepository postRepository;
    
    @Autowired
    private CategoryRepository categoryRepository;
    
    public List<UserPostDTO> getUserPosts(Long userId) {
        User user = userRepository.findById(userId);
        List<Post> posts = postRepository.findByUserId(userId);
        
        return posts.stream()
                   .map(post -> {
                       Category category = categoryRepository.findById(post.getCategoryId());
                       return new UserPostDTO(user.getName(), post.getTitle(), category.getName());
                   })
                   .collect(Collectors.toList());
    }
}
``

### 11.9 结合设计模式的整洁代码实践

将设计模式与代码整洁实践相结合,可以进一步提高代码质量:

1. **工厂模式 + 参数校验**:在创建对象时进行参数校验
2. **建造者模式 + 早期返回**:在建造过程中进行有效性检查
3. **策略模式 + 枚举**:使用枚举来管理不同的策略
4. **模板方法模式 + 提前返回**:在模板方法中使用守卫子句

通过遵循这些代码整洁实践,可以确保您的代码不仅使用了正确的设计模式,还具备良好的可读性、可维护性和健壮性。
相关推荐
宵时待雨2 小时前
数据结构(初阶)笔记归纳6:双向链表的实现
c语言·开发语言·数据结构·笔记·算法·链表
xixi09242 小时前
selenium——浏览器基础操作(启动/访问/窗口控制)
开发语言·python
不吃洋葱.2 小时前
js主要内容
开发语言·javascript·ecmascript
Rhys..2 小时前
python + selenium 如何定位动态元素
开发语言·python·selenium
源代码•宸2 小时前
Golang原理剖析(GMP调度原理)
开发语言·经验分享·后端·面试·golang·gmp·runnext
LawrenceLan2 小时前
Flutter 零基础入门(二十三):Icon、Image 与资源管理
开发语言·前端·flutter·dart
m0_748252382 小时前
Java 变量类型
java·数据结构·windows
余衫马2 小时前
Qt for Python:PySide6 入门指南(中篇)
开发语言·c++·python·qt
老蒋每日coding2 小时前
AI Agent 设计模式系列(十一)—— 目标设定和监控模式
人工智能·设计模式·langchain