秋招Java后端开发冲刺——设计模式

发布于:2024-07-02 ⋅ 阅读:(16) ⋅ 点赞:(0)

本文介绍Java中的代理模式,及一些常见的模式应用。

一、Java设计模式

Java中最常见的设计模式主要有23种,如表所示:

表格:Java设计模式分类

类型 设计模式
创建型模式 单例模式(Singleton Pattern)
工厂方法模式(Factory Method Pattern)
抽象工厂模式(Abstract Factory Pattern)
建造者模式(Builder Pattern)
原型模式(Prototype Pattern)
结构型模式 适配器模式(Adapter Pattern)
桥接模式(Bridge Pattern)
组合模式(Composite Pattern)
装饰者模式(Decorator Pattern)
外观模式(Facade Pattern)
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)
行为型模式 责任链模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
解释器模式(Interpreter Pattern)
迭代器模式(Iterator Pattern)
中介者模式(Mediator Pattern)
备忘录模式(Memento Pattern)
观察者模式(Observer Pattern)
状态模式(State Pattern)
策略模式(Strategy Pattern)
模板方法模式(Template Method Pattern)
访问者模式(Visitor Pattern)

二、单例模式(美团面试真题)

单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点来访问该实例。这种模式通常用于需要全局唯一实例的场景,如配置管理、日志记录、数据库连接等。单例模式可分为饿汉式和懒汉式两种。

1. 饿汉式(线程安全):在类加载时就创建实例,但是可能会造成资源浪费。
代码实现:

public class Singleton {
    private static final Singleton instance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return instance;
    }
}

2. 懒汉式:在使用时才创建对象实例,因此面对多线程时会产生线程安全问题。
代码:

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

3. 线程安全的单例模式(使用双重锁)

public class Singleton{
    private static Singleton instance;
    private Singleton(){}
    //获取单例的方法
    public static  Singleton getInstance(){
        //第一重校验
        if(instance == null){
            synchronized (Singleton.class){
                //第二重校验
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

三、工厂方法模式 VS 抽象方法模式

1. 工厂方法模式

  • 工厂方法模式为每种产品创建一个具体工厂类,然后在使用时根据需要使用相应的具体工厂创建对象
  • 优点:符合开闭原则,可以增加新的产品类而无需修改现有代码
  • 缺点:需要为每种产品创建一个具体工厂类,增加了系统的复杂度和代码量
  • 示例
// 产品接口
interface Product {
    void use();
}

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

// 具体产品B
class ConcreteProductB implements Product {
    public void use() {
        System.out.println("Using Product B");
    }
}

// 抽象工厂
abstract class Creator {
    public abstract Product factoryMethod();
}

// 具体工厂A
class ConcreteCreatorA extends Creator {
    public Product factoryMethod() {
        return new ConcreteProductA();
    }
}

// 具体工厂B
class ConcreteCreatorB extends Creator {
    public Product factoryMethod() {
        return new ConcreteProductB();
    }
}
public class Client {
    public static void main(String[] args) {
        Creator creatorA = new ConcreteCreatorA();
        Product productA = creatorA.factoryMethod();
        productA.use(); // 输出: Using Product A

        Creator creatorB = new ConcreteCreatorB();
        Product productB = creatorB.factoryMethod();
        productB.use(); // 输出: Using Product B
    }
}

2. 抽象方法模式

  • 抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
  • 优点
    ① 分离了具体类的生成,使得产品之间的依赖关系更加一致。
    ② 提供了一个一致的接口,可以创建多个产品对象,使产品族的更换变得容易
  • 缺点:新增产品族时需要修改抽象工厂接口,违反了开闭原则,增加复杂性
  • 示例
// 抽象产品A
interface ProductA {
    void use();
}

// 抽象产品B
interface ProductB {
    void use();
}

// 具体产品A1
class ConcreteProductA1 implements ProductA {
    public void use() {
        System.out.println("Using Product A1");
    }
}

// 具体产品B1
class ConcreteProductB1 implements ProductB {
    public void use() {
        System.out.println("Using Product B1");
    }
}

// 具体产品A2
class ConcreteProductA2 implements ProductA {
    public void use() {
        System.out.println("Using Product A2");
    }
}

// 具体产品B2
class ConcreteProductB2 implements ProductB {
    public void use() {
        System.out.println("Using Product B2");
    }
}

// 抽象工厂
interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
    public ProductA createProductA() {
        return new ConcreteProductA1();
    }

    public ProductB createProductB() {
        return new ConcreteProductB1();
    }
}

// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {
    public ProductA createProductA() {
        return new ConcreteProductA2();
    }

    public ProductB createProductB() {
        return new ConcreteProductB2();
    }
}
public class Client {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        ProductA productA1 = factory1.createProductA();
        ProductB productB1 = factory1.createProductB();
        productA1.use(); // 输出: Using Product A1
        productB1.use(); // 输出: Using Product B1

        AbstractFactory factory2 = new ConcreteFactory2();
        ProductA productA2 = factory2.createProductA();
        ProductB productB2 = factory2.createProductB();
        productA2.use(); // 输出: Using Product A2
        productB2.use(); // 输出: Using Product B2
    }
}

3. 二者区别(华为面试)

特性 工厂方法模式 (Factory Method) 抽象工厂模式 (Abstract Factory)
定义 定义一个创建对象的接口,但由子类决定实例化哪个类。 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
使用场景 当一个类不知道它所需要的对象的具体类时。 当系统要独立于它的产品的创建、组合和表示时。
优点 1. 符合开闭原则。
2. 客户端不需要修改代码就可以使用新创建的对象。
1. 分离了具体类的生成。
2. 提供了一致的接口,便于创建多个相关产品对象。
缺点 1. 需要为每种产品创建一个具体工厂类。
2. 增加了系统的复杂度和代码量。
1. 新增产品族时需要修改抽象工厂接口,违反开闭原则。
2. 增加了系统的复杂度。
主要角色 1. 抽象产品
2. 具体产品
3. 抽象工厂
4. 具体工厂
1. 抽象产品
2. 具体产品
3. 抽象工厂
4. 具体工厂
产品创建的粒度 只创建单一产品对象。 创建一系列相关或依赖的产品对象。

四、策略模式

1. 定义
定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。本模式使得算法可以独立于使用它的客户而变化。
2. 示例

interface Strategy {
    void execute();
}

class ConcreteStrategyA implements Strategy {
    @Override
    public void execute() {
        System.out.println("Strategy A executed.");
    }
}

class ConcreteStrategyB implements Strategy {
    @Override
    public void execute() {
        System.out.println("Strategy B executed.");
    }
}

class Context {
    private Strategy strategy;
    
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public void executeStrategy() {
        strategy.execute();
    }
}
  1. 常见应用

五、观察者模式

1. 定义
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
2. 示例(海康威视笔试:楼层着火通知)

// 观察者接口
interface Observer {
    void update(int floor); // 更新方法,传入楼层信息
}
// 具体的观察者类(保安类)
class SecurityGuard implements Observer {
    private String name;
    
    public SecurityGuard(String name) {
        this.name = name;
    }

    @Override
    public void update(int floor) {
        System.out.println("Security Guard " + name + " received fire alert from floor " + floor);
        if (floor == Integer.parseInt(name)) {
            System.out.println("Security Guard " + name + " is handling the fire.");
        } else {
            System.out.println("Security Guard " + name + " is not responsible for this floor.");
        }
    }
}
// 被观察者接口
interface  Subject{
    void registerObserver(Observer observer); // 注册观察者
    void removeObserver(Observer observer); // 移除观察者
    void notifyObservers(int floor); // 通知观察者
}

// 具体主题类(楼层类)
class Floor implements Subject {
    private List<Observer> observers; // 观察者列表

    public Floor() {
        this.observers = new ArrayList<>();
    }

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

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

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

    // 模拟楼层着火
    public void fireAlert(int floor) {
        System.out.println("Fire alert on floor " + floor);
        notifyObservers(floor);
    }
}

六、外观模式

  1. 定义
    为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这一接口使得这一子系统更加容易使用
  2. 示例(海康笔试:以电脑启动为例)
// CPU 类
class CPU {
    public void start() {
        System.out.println("CPU is starting...");
    }
}

// Disk 类
class Disk {
    public void start() {
        System.out.println("Disk is starting...");
    }
}

// Memory 类
class Memory {
    public void start() {
        System.out.println("Memory is starting...");
    }
}

// 外观类
class ComputerFacade {
    private CPU cpu;
    private Disk disk;
    private Memory memory;

    public ComputerFacade() {
        this.cpu = new CPU();
        this.disk = new Disk();
        this.memory = new Memory();
    }

    public void startComputer() {
        System.out.println("Starting computer...");
        disk.start();
        cpu.start();
        memory.start();
        System.out.println("Computer started successfully.");
    }
}

七、责任链模式

1. 定义
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
2. 示例

在这里插入代码片abstract class Handler {
    protected Handler successor;
    
    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }
    
    public abstract void handleRequest(int request);
}
class ConcreteHandler1 extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request < 10) {
            System.out.println("Handler1 handled request " + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}
class ConcreteHandler2 extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request >= 10) {
            System.out.println("Handler2 handled request " + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

八、Java IO中设计模式

  1. 装饰者模式
    装饰者模式允许动态地将职责添加到对象中,通过将对象封装在装饰对象中来增强对象的功能。(InputStream 和 OutputStream 及其子类)
    2. 适配器模式
    适配器模式允许将一个类的接口转换为另一个接口,以便不同接口的类可以一起工作。(InputStreamReader 和 OutputStreamWriter 类)
    3. 桥接模式
    桥接模式用于将抽象部分与它的实现部分分离,使它们可以独立变化。(Reader 和 Writer 抽象类及其具体实现类)
    4. 迭代器模式
    迭代器模式用于提供一种方法来顺序访问集合中的每个元素,而不暴露其底层表示。(Scanner 类用于逐行读取输入)
    5. 责任链模式
    FilterInputStream 和 FilterOutputStream 类
    6. 工厂方法模式
    FileReader 和 FileWriter 类