Java常用设计模式详解

发布于:2025-06-27 ⋅ 阅读:(15) ⋅ 点赞:(0)

引言

设计模式是软件开发中解决特定问题的成熟方案,是前人经验的总结。在Java开发中,合理使用设计模式可以提高代码的可复用性、可维护性、可读性和可靠性。

一、工厂模式

1. 概述

工厂模式是Java中最常用的创建型设计模式之一,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

工厂模式可以分为三类:简单工厂模式工厂方法模式抽象工厂模式。其中简单工厂模式不属于GoF 23种设计模式,但它们都属于创建型模式。

2. 简单工厂模式

简单工厂模式又称为静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

2.1 结构

  • 抽象产品(Product):定义产品的接口
  • 具体产品(ConcreteProduct):实现了抽象产品接口
  • 工厂(Factory):负责创建产品对象

2.2 代码示例

// 抽象产品
interface Shape {
    void draw();
}

// 具体产品
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个矩形");
    }
}

class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个正方形");
    }
}

// 工厂类
class ShapeFactory {
    // 使用getShape方法获取形状类型的对象
    public Shape getShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }
        if (shapeType.equalsIgnoreCase("CIRCLE")) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
            return new Rectangle();
        } else if (shapeType.equalsIgnoreCase("SQUARE")) {
            return new Square();
        }
        return null;
    }
}

// 客户端代码
public class FactoryPatternDemo {
    public static void main(String[] args) {
        ShapeFactory shapeFactory = new ShapeFactory();

        // 获取 Circle 的对象,并调用它的 draw 方法
        Shape shape1 = shapeFactory.getShape("CIRCLE");
        shape1.draw();

        // 获取 Rectangle 的对象,并调用它的 draw 方法
        Shape shape2 = shapeFactory.getShape("RECTANGLE");
        shape2.draw();

        // 获取 Square 的对象,并调用它的 draw 方法
        Shape shape3 = shapeFactory.getShape("SQUARE");
        shape3.draw();
    }
}

3. 工厂方法模式

工厂方法模式是简单工厂模式的进一步抽象和推广。在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说每个对象都有一个与之对应的工厂。

3.1 结构

  • 抽象产品(Product):定义产品的接口
  • 具体产品(ConcreteProduct):实现抽象产品接口
  • 抽象工厂(Factory):声明工厂方法,返回一个产品对象
  • 具体工厂(ConcreteFactory):实现工厂方法,返回一个具体产品实例

3.2 代码示例

// 抽象产品
interface Shape {
    void draw();
}

// 具体产品
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个矩形");
    }
}

// 抽象工厂
abstract class ShapeFactory {
    public abstract Shape getShape();
}

// 具体工厂
class CircleFactory extends ShapeFactory {
    @Override
    public Shape getShape() {
        return new Circle();
    }
}

class RectangleFactory extends ShapeFactory {
    @Override
    public Shape getShape() {
        return new Rectangle();
    }
}

// 客户端代码
public class FactoryMethodDemo {
    public static void main(String[] args) {
        ShapeFactory circleFactory = new CircleFactory();
        Shape circle = circleFactory.getShape();
        circle.draw();

        ShapeFactory rectangleFactory = new RectangleFactory();
        Shape rectangle = rectangleFactory.getShape();
        rectangle.draw();
    }
}

4. 抽象工厂模式

抽象工厂模式是工厂方法模式的升级版本,它用来创建一组相关或者相互依赖的对象。抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

4.1 结构

  • 抽象产品(AbstractProduct):为一类产品定义接口
  • 具体产品(ConcreteProduct):实现抽象产品接口
  • 抽象工厂(AbstractFactory):声明一组创建产品的方法
  • 具体工厂(ConcreteFactory):实现抽象工厂定义的方法

4.2 代码示例

// 抽象产品A
interface Shape {
    void draw();
}

// 具体产品A1, A2
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个矩形");
    }
}

// 抽象产品B
interface Color {
    void fill();
}

// 具体产品B1, B2
class Red implements Color {
    @Override
    public void fill() {
        System.out.println("填充红色");
    }
}

class Blue implements Color {
    @Override
    public void fill() {
        System.out.println("填充蓝色");
    }
}

// 抽象工厂
interface AbstractFactory {
    Shape getShape(String shape);
    Color getColor(String color);
}

// 具体工厂1
class ShapeFactory implements AbstractFactory {
    @Override
    public Shape getShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }
        if (shapeType.equalsIgnoreCase("CIRCLE")) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
            return new Rectangle();
        }
        return null;
    }

    @Override
    public Color getColor(String color) {
        return null;
    }
}

// 具体工厂2
class ColorFactory implements AbstractFactory {
    @Override
    public Shape getShape(String shapeType) {
        return null;
    }

    @Override
    public Color getColor(String color) {
        if (color == null) {
            return null;
        }
        if (color.equalsIgnoreCase("RED")) {
            return new Red();
        } else if (color.equalsIgnoreCase("BLUE")) {
            return new Blue();
        }
        return null;
    }
}

// 工厂生成器
class FactoryProducer {
    public static AbstractFactory getFactory(String choice) {
        if (choice.equalsIgnoreCase("SHAPE")) {
            return new ShapeFactory();
        } else if (choice.equalsIgnoreCase("COLOR")) {
            return new ColorFactory();
        }
        return null;
    }
}

// 客户端代码
public class AbstractFactoryDemo {
    public static void main(String[] args) {
        // 获取形状工厂
        AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");

        // 获取形状为 Circle 的对象
        Shape shape1 = shapeFactory.getShape("CIRCLE");
        shape1.draw();

        // 获取形状为 Rectangle 的对象
        Shape shape2 = shapeFactory.getShape("RECTANGLE");
        shape2.draw();

        // 获取颜色工厂
        AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");

        // 获取颜色为 Red 的对象
        Color color1 = colorFactory.getColor("RED");
        color1.fill();

        // 获取颜色为 Blue 的对象
        Color color2 = colorFactory.getColor("BLUE");
        color2.fill();
    }
}

5. 工厂模式的优缺点

5.1 优点

  • 降低耦合度:工厂模式将对象的创建和使用分离,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可。
  • 扩展性高:如果想增加一个产品,只要扩展一个工厂类和产品类即可。
  • 屏蔽产品的具体实现:客户端只关心产品的接口,不关心产品的具体实现。

5.2 缺点

  • 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这无疑会增加系统的复杂度。
  • 抽象工厂模式难以支持新种类产品的变化:如果需要添加新的产品种类,就需要修改抽象工厂的接口,这将涉及到所有的具体工厂类,违背了"开闭原则"。

6. 应用场景

  1. JDK中的应用java.util.CalendarResourceBundleNumberFormat等的getInstance()方法。
  2. Spring框架中的应用:BeanFactory就是简单工厂模式的体现,用来创建对象的实例。
  3. JDBC中的应用Connection对象的获取、PreparedStatement对象的获取等。

二、策略模式

1. 概述

策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换,且算法的变化不会影响到使用算法的客户。策略模式让算法独立于使用它的客户而变化。

2. 结构

  • 策略接口(Strategy):定义了一个算法族,它们都实现了相同的接口
  • 具体策略(ConcreteStrategy):实现了策略接口的具体算法
  • 上下文(Context):持有一个策略类的引用,最终给客户端调用

3. 代码示例

// 策略接口
interface PayStrategy {
    boolean pay(int paymentAmount);
    void collectPaymentDetails();
}

// 具体策略1
class PayByPayPal implements PayStrategy {
    private String email;
    private String password;
    private boolean signedIn;

    @Override
    public void collectPaymentDetails() {
        // 模拟收集支付宝支付详情
        email = "test@example.com";
        password = "password";
        signedIn = true;
        System.out.println("收集支付宝支付详情");
    }

    @Override
    public boolean pay(int paymentAmount) {
        if (signedIn) {
            System.out.println("使用支付宝支付 " + paymentAmount + " 元");
            return true;
        } else {
            return false;
        }
    }
}

// 具体策略2
class PayByCreditCard implements PayStrategy {
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;
    private boolean cardPresent;

    @Override
    public void collectPaymentDetails() {
        // 模拟收集信用卡支付详情
        cardNumber = "1234 5678 9012 3456";
        cvv = "123";
        dateOfExpiry = "12/25";
        cardPresent = true;
        System.out.println("收集信用卡支付详情");
    }

    @Override
    public boolean pay(int paymentAmount) {
        if (cardPresent) {
            System.out.println("使用信用卡支付 " + paymentAmount + " 元");
            return true;
        } else {
            return false;
        }
    }
}

// 上下文
class Order {
    private int totalCost = 0;
    private boolean isClosed = false;
    private PayStrategy strategy;

    public void processOrder(PayStrategy strategy) {
        this.strategy = strategy;
        strategy.collectPaymentDetails();
    }

    public void setTotalCost(int cost) {
        this.totalCost = cost;
    }

    public int getTotalCost() {
        return totalCost;
    }

    public boolean isClosed() {
        return isClosed;
    }

    public void setClosed() {
        isClosed = true;
    }

    public boolean payOrder() {
        return strategy.pay(totalCost);
    }
}

// 客户端代码
public class StrategyPatternDemo {
    public static void main(String[] args) {
        Order order = new Order();
        order.setTotalCost(1000);

        // 使用支付宝支付
        order.processOrder(new PayByPayPal());
        order.payOrder();

        System.out.println("-------------------");

        // 使用信用卡支付
        order.processOrder(new PayByCreditCard());
        order.payOrder();
    }
}

4. 策略模式的优缺点

4.1 优点

  • 算法可以自由切换:只要实现了策略接口,就可以自由切换算法。
  • 避免使用多重条件判断:如果不使用策略模式,对于不同的算法,需要使用多重条件判断。
  • 扩展性良好:增加新的策略只需要实现策略接口即可,不需要修改原有代码。

4.2 缺点

  • 策略类会增多:每一个策略都是一个类,复用的可能性很小。
  • 所有策略类都需要对外暴露:上层模块必须知道有哪些策略,才能决定使用哪一个策略。

5. 应用场景

  1. 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为
  2. 需要在不同情况下使用不同的算法,或者策略还可能在未来用其它方式来实现
  3. 对客户隐藏具体策略(算法)的实现细节

6. JDK中的应用

  1. java.util.Comparator#compare():用于排序集合。
  2. javax.servlet.http.HttpServletservice()方法,以及所有doXXX()方法。
  3. javax.servlet.Filter#doFilter()

三、观察者模式

1. 概述

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

2. 结构

  • 主题(Subject):被观察的对象,当需要被观察的状态发生变化时,需要通知队列中所有观察者
  • 观察者(Observer):接收主题通知并进行更新,对主题的状态变化做出反应
  • 具体主题(ConcreteSubject):具体的被观察者,存储相关状态,当状态发生变化时,向观察者发出通知
  • 具体观察者(ConcreteObserver):具体的观察者,实现观察者接口,接收主题的状态变化并进行相应处理

3. 代码示例

import java.util.ArrayList;
import java.util.List;

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

// 主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 具体主题
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String message;

    @Override
    public void registerObserver(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();
    }
}

// 具体观察者1
class ConcreteObserver1 implements Observer {
    private String name;

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

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

// 具体观察者2
class ConcreteObserver2 implements Observer {
    private String name;

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

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

// 客户端代码
public class ObserverPatternDemo {
    public static void main(String[] args) {
        // 创建主题
        ConcreteSubject subject = new ConcreteSubject();

        // 创建观察者
        Observer observer1 = new ConcreteObserver1("观察者1");
        Observer observer2 = new ConcreteObserver2("观察者2");

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

        // 改变主题状态
        subject.setMessage("第一条消息");

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

        // 再次改变主题状态
        subject.setMessage("第二条消息");
    }
}

4. 观察者模式的优缺点

4.1 优点

  • 观察者和被观察者之间是抽象耦合:观察者和被观察者之间是抽象耦合的,被观察者只知道观察者实现了某一接口,并不需要知道具体实现类是谁,具体实现了什么。
  • 建立一套触发机制:观察者模式建立了一套触发机制,当被观察者发生变化时,会自动通知观察者。

4.2 缺点

  • 观察者较多时可能会影响性能:如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
  • 观察者与被观察者之间存在循环依赖:观察者与被观察者之间如果存在循环依赖,可能导致系统崩溃。
  • 没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的:而仅仅只是知道观察目标发生了变化。

3.5 应用场景

  • 对一个对象状态的更新,需要其他对象同步更新:当一个对象的改变需要同时改变其它对象,或者一个对象的改变对其它对象造成影响,可以使用观察者模式。
  • 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节:当一个抽象模型有两个方面,其中一个方面依赖于另一方面,可以使用观察者模式将这两者封装在独立的对象中使它们可以各自独立地改变和复用。

6. JDK中的应用

  1. java.util.Observerjava.util.Observable(已废弃)
  2. java.util.EventListener的所有实现
  3. javax.servlet.http.HttpSessionBindingListener
  4. javax.servlet.http.HttpSessionAttributeListener

四、装饰器模式

1. 概述

装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

2. 结构

  • 抽象组件(Component):定义一个抽象接口以规范准备接收附加责任的对象
  • 具体组件(ConcreteComponent):实现抽象组件,是被装饰的原始对象
  • 抽象装饰器(Decorator):继承抽象组件,并持有一个抽象组件的引用
  • 具体装饰器(ConcreteDecorator):实现抽象装饰器的相关方法,并给具体组件对象添加附加的责任

3. 代码示例

// 抽象组件
interface Component {
    void operation();
}

// 具体组件
class ConcreteComponent implements Component {
    @Override
    public void operation() {
        System.out.println("具体组件的基本操作");
    }
}

// 抽象装饰器
abstract class Decorator implements Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        component.operation();
    }
}

// 具体装饰器A
class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addedBehavior();
    }

    // 额外的方法
    private void addedBehavior() {
        System.out.println("装饰器A添加的功能");
    }
}

// 具体装饰器B
class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addedBehavior();
    }

    // 额外的方法
    private void addedBehavior() {
        System.out.println("装饰器B添加的功能");
    }
}

// 客户端代码
public class DecoratorPatternDemo {
    public static void main(String[] args) {
        // 创建具体组件
        Component component = new ConcreteComponent();
        
        // 用装饰器A装饰
        Component decoratorA = new ConcreteDecoratorA(component);
        decoratorA.operation();
        
        System.out.println("-------------------");
        
        // 用装饰器B装饰
        Component decoratorB = new ConcreteDecoratorB(component);
        decoratorB.operation();
        
        System.out.println("-------------------");
        
        // 用装饰器B装饰已经被装饰器A装饰过的对象
        Component decoratorBA = new ConcreteDecoratorB(decoratorA);
        decoratorBA.operation();
    }
}

4. 装饰器模式的优缺点

4.1 优点

  • 装饰类和被装饰类可以独立发展,不会相互耦合:装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
  • 装饰模式是继承的一个替代方案:通过组合而非继承来扩展对象的功能,相比继承更加灵活。
  • 可以动态地扩展一个对象的功能:通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。

4.2 缺点

会产生很多小对象:装饰模式需要创建一个装饰类,如果需要装饰的功能很多,会产生很多小对象,增加系统的复杂度。
多层装饰比较复杂:如果一个对象被多个装饰器所装饰,调试时寻找错误可能需要逐级排查,较为繁琐。

5. 应用场景

  • 需要扩展一个类的功能,或给一个类添加附加职责
  • 需要动态地给一个对象添加功能,这些功能可以再动态地撤销
  • 需要为一批兄弟类进行改装或加装功能,当然是首选装饰模式

6. JDK中的应用

  1. java.io包中的各种输入输出流,如BufferedInputStreamDataInputStream等。
  2. java.util.Collections#checkedXXX()synchronizedXXX()unmodifiableXXX()方法。
  3. javax.servlet.http.HttpServletRequestWrapperHttpServletResponseWrapper

五、适配器模式

1. 概述

适配器模式(Adapter Pattern)是一种结构型设计模式,它将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类适配器模式和对象适配器模式。

2. 结构

  • 目标接口(Target):客户所期待的接口
  • 适配者类(Adaptee):需要适配的类
  • 适配器类(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口

3. 类适配器模式

类适配器模式是通过继承来实现适配器功能的,适配器继承了适配者类,同时实现了目标接口。

3.1 代码示例

// 目标接口
interface Target {
    void request();
}

// 适配者类
class Adaptee {
    public void specificRequest() {
        System.out.println("适配者的特殊请求");
    }
}

// 类适配器
class ClassAdapter extends Adaptee implements Target {
    @Override
    public void request() {
        specificRequest();
    }
}

// 客户端代码
public class ClassAdapterDemo {
    public static void main(String[] args) {
        Target target = new ClassAdapter();
        target.request();
    }
}

4. 对象适配器模式

对象适配器模式是通过组合来实现适配器功能的,适配器持有适配者类的实例,同时实现了目标接口。

4.1 代码示例

// 目标接口
interface Target {
    void request();
}

// 适配者类
class Adaptee {
    public void specificRequest() {
        System.out.println("适配者的特殊请求");
    }
}

// 对象适配器
class ObjectAdapter implements Target {
    private Adaptee adaptee;

    public ObjectAdapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}

// 客户端代码
public class ObjectAdapterDemo {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new ObjectAdapter(adaptee);
        target.request();
    }
}

5. 适配器模式的优缺点

5.1 优点

  • 将目标类和适配者类解耦:通过引入一个适配器类来重用现有的适配者类,无须修改原有结构。
  • 增加了类的透明性和复用性:将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性。
  • 灵活性和扩展性都很好:通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合"开闭原则"。

5.2 缺点

  • 过多地使用适配器会让系统非常零乱:明明看到调用的是A接口,内部却被适配成了B接口的实现,如果不是必要,不要使用适配器。
  • 由于Java至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类

6. 应用场景

  1. 系统需要使用现有的类,而这些类的接口不符合系统的需要
  2. 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作

7. JDK中的应用

  1. java.util.Arrays#asList()
  2. java.io.InputStreamReader(InputStream)
  3. java.io.OutputStreamWriter(OutputStream)

六、模板方法模式

1. 概述

模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

2. 结构

  • 抽象类(AbstractClass):定义抽象的原语操作(primitive operation),具体的子类将重定义它们以实现一个算法的各步骤,实现一个模板方法作为算法的骨架
  • 具体类(ConcreteClass):实现原语操作以完成算法中与特定子类相关的步骤

3. 代码示例

// 抽象类
abstract class AbstractClass {
    // 模板方法
    public final void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
        concreteOperation();
        hook();
    }

    // 基本方法—具体方法
    public void concreteOperation() {
        System.out.println("抽象类中的具体方法");
    }

    // 基本方法—抽象方法
    protected abstract void primitiveOperation1();
    protected abstract void primitiveOperation2();

    // 钩子方法
    protected void hook() {
        // 默认实现,子类可以选择性覆盖
    }
}

// 具体类A
class ConcreteClassA extends AbstractClass {
    @Override
    protected void primitiveOperation1() {
        System.out.println("具体类A的方法1实现");
    }

    @Override
    protected void primitiveOperation2() {
        System.out.println("具体类A的方法2实现");
    }

    @Override
    protected void hook() {
        System.out.println("具体类A覆盖了钩子方法");
    }
}

// 具体类B
class ConcreteClassB extends AbstractClass {
    @Override
    protected void primitiveOperation1() {
        System.out.println("具体类B的方法1实现");
    }

    @Override
    protected void primitiveOperation2() {
        System.out.println("具体类B的方法2实现");
    }
}

// 客户端代码
public class TemplateMethodDemo {
    public static void main(String[] args) {
        AbstractClass a = new ConcreteClassA();
        a.templateMethod();

        System.out.println("-------------------");

        AbstractClass b = new ConcreteClassB();
        b.templateMethod();
    }
}

4. 模板方法模式的优缺点

4.1 优点

  • 封装不变部分,扩展可变部分:把不变的行为搬移到超类,去除子类中的重复代码。
  • 提取公共代码,便于维护:将相同部分的代码放在父类中,提高代码复用性。
  • 行为由父类控制,子类实现:基本方法是由子类实现的,因此子类可以通过扩展的方式增加相应的功能,符合开闭原则。

4.2 缺点

  • 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大
  • 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度

5. 应用场景

  1. 算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现
  2. 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制

6. JDK中的应用

  1. java.io.InputStreamjava.io.OutputStreamjava.io.Readerjava.io.Writerread()write()方法。
  2. java.util.AbstractListjava.util.AbstractSetjava.util.AbstractMap的实现。
  3. javax.servlet.http.HttpServletdoGet()doPost()等方法。

总结

本文详细介绍了Java中最常用的六种设计模式:工厂模式、策略模式、观察者模式、装饰器模式、适配器模式和模板方法模式。这些设计模式在Java开发中有着广泛的应用,掌握它们可以帮助我们写出更加灵活、可维护的代码。

每种设计模式都有其特定的应用场景和优缺点,在实际开发中,我们需要根据具体的需求选择合适的设计模式。同时,设计模式并不是银弹,过度使用设计模式可能会导致系统变得复杂,因此我们需要在实际应用中权衡利弊,合理使用设计模式。