java基础知识④:设计模式

目录

一、设计模式

1️⃣创建型设计模式(常用:单例、工厂、抽象工厂)

2️⃣结构型设计模式(常用:适配器、装饰者、外观、代理)

3️⃣行为型设计模式(常用:观察者、策略、模板方法、命令)

二、其他

4️⃣面试中关于设计模式如何考察(思考该如何回答?在实际项目中如何应用?)


具体详细说明如下:

带着问题学习:👀什么是设计模式?设计模式包含哪些?每个设计模式的特点又都是什么?每个设计模式有都适用于哪些场景?

设计模式是软件工程中的一种解决问题的方法论,它提供了一套经过测试和验证的代码设计原则和模板。设计模式有助于构建可维护、可扩展和可重用的代码,提高软件系统的灵活性和可靠性。在Java中,常用的设计模式包括创建型模式、结构型模式和行为型模式。在Java中,设计模式包括常见的23种,常用6~8种。在Java中,常用的设计模式📣包括创建型模式、结构型模式和行为型模式。下面将详细讨论这些设计模式,并举例说明其用法。 

一、设计模式

设计模式的原则(六大原则):

  1. 单一职责原则(Single Responsibility Principle, SRP):这个原则要求一个类应该只有一个引起变化的原因。在Java中,可以通过将类和方法拆分成更小的部分,使得每个类和方法只负责一个特定的职责。

  2. 开放-封闭原则(Open-Closed Principle, OCP):这个原则要求软件实体应该对扩展开放,对修改封闭。在Java中,可以通过使用接口、抽象类和设计模式(如策略模式、装饰器模式)来实现。

  3. 里氏替换原则(Liskov Substitution Principle, LSP):在Java中,这个原则要求子类可以替换父类并且仍然能够在程序中工作。通过合理设计继承关系和使用接口,可以实现这个原则。

  4. 依赖倒置原则(Dependency Inversion Principle, DIP):这个原则要求高层模块不应该依赖于低层模块,两者都应该依赖于抽象。在Java中,可以通过依赖注入(如使用Spring框架)来实现。

  5. 接口隔离原则(Interface Segregation Principle, ISP):这个原则要求一个类不应该强迫实现它用不到的接口。在Java中,可以通过定义多个小接口,避免一个庞大的接口。

  6. 最少知识原则(Least Knowledge Principle, LKP):这个原则要求一个软件实体尽可能少地了解其他实体。在Java中,可以通过合理的使用设计模式来实现。

 注:图片来源于网络,版权归属原作者

1️⃣创建型设计模式(常用:单例、工厂、抽象工厂)

 注:图片来源于网络,版权归属原作者
  •  单例模式(Singleton):确保一个类只有一个实例,并提供一个全局访问点。典型的应用场景是线程池、数据库连接池等。或比如在一个Web应用程序中,可能需要一个全局的配置管理类,保证程序运行期间只有一个配置实例。示例代码如下:

在项目中通常会有一些需要全局唯一的资源或服务,比如配置管理器、线程池等。使用单例模式可以确保只创建一个实例,避免资源浪费和不一致性

// 示例一
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;
    }
}

// ==================================================================
// 示例二
public class AppConfig {
    private static AppConfig instance;

    private AppConfig() {
        // 私有构造函数,防止外部实例化
    }

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

    public String getConfiguration(String key) {
        // 实现获取配置信息的方法
    }
}
  • 工厂模式(Factory):工厂模式通过提供一个公共的接口来实例化对象(定义一个用于创建对象的接口),隐藏了具体实现类的创建逻辑,让子类决定实例化哪个类。常见的场景是数据库操作类的创建。工厂方法模式(Factory Method Pattern):在项目中经常用于创建对象,尤其是在需要根据条件创建不同类型对象时。比如,可以根据不同的请求参数创建不同类型的数据库连接、日志记录器等对象。

在项目中,可以创建一个抽象工厂接口和多个具体工厂实现类,用于根据条件创建不同类型的对象。例如,可以创建一个数据库连接的抽象工厂接口,如ConnectionFactory,并实现多个具体工厂类,如MysqlConnectionFactoryPostgresqlConnectionFactory。在需要创建数据库连接时,通过工厂方法根据条件创建不同类型的数据库连接对象。 

public interface Database {
    void connect();
    void disconnect();
}

public class MySQLDatabase implements Database {
    @Override
    public void connect() {
        // 连接MySQL数据库的具体逻辑
    }

    @Override
    public void disconnect() {
        // 断开连接MySQL数据库的具体逻辑
    }
}

public class OracleDatabase implements Database {
    @Override
    public void connect() {
        // 连接Oracle数据库的具体逻辑
    }

    @Override
    public void disconnect() {
        // 断开连接Oracle数据库的具体逻辑
    }
}

public class DatabaseFactory {
    public static Database createDatabase(String type) {
        if (type.equals("MySQL")) {
            return new MySQLDatabase();
        } else if (type.equals("Oracle")) {
            return new OracleDatabase();
        }
        throw new IllegalArgumentException("Invalid database type: " + type);
    }
}

比如在一个图形界面应用程序中,根据用户选择的图形类型创建相应的图形对象,可以用工厂模式。示例代码如下:

public interface Shape {
    void draw();
}

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Draw a circle");
    }
}

public class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("Draw a square");
    }
}

public class ShapeFactory {
    public Shape createShape(String type) {
        if ("circle".equalsIgnoreCase(type)) {
            return new Circle();
        } else if ("square".equalsIgnoreCase(type)) {
            return new Square();
        }
        return null;
    }
}
  • 抽象工厂模式(Abstract Factory):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。典型的应用场景是GUI库,其中不同操作系统下的按钮、文本框等控件有不同的具体实现。
public interface Button {
    void render();
}

public class WindowsButton implements Button {
    @Override
    public void render() {
        // 在Windows操作系统下渲染按钮的具体逻辑
    }
}

public class MacOSButton implements Button {
    @Override
    public void render() {
        // 在MacOS操作系统下渲染按钮的具体逻辑
    }
}

public interface GUIFactory {
    Button createButton();
}

public class WindowsGUIFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }
}

public class MacOSGUIFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacOSButton();
    }
}

2️⃣结构型设计模式(常用:适配器、装饰者、外观、代理)

 注:图片来源于网络,版权归属原作者
  • 适配器模式(Adapter):将一个类的接口转换为客户希望的另一个接口。

在项目中需要将一个接口转换成另一个客户端需要的接口时,可以使用适配器模式。比如,将第三方库的接口适配成项目内部需要的接口、旧版本的代码中使用新版本的接口。

public interface Target {
    void request();
}

public class Adaptee {
    public void specificRequest() {
        // 适配者类的特殊请求的具体逻辑
    }
}

public class Adapter implements Target {
    private Adaptee adaptee;

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

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}
  • 装饰者模式(Decorator):动态地给一个对象添加一些额外的职责。装饰器模式允许动态地向对象添加额外的行为。它是通过将对象包装在一个装饰器类中来实现的,该类有与原始对象相同的接口。

在项目中需要对一个对象进行动态地添加功能或修改现有功能时,可以使用装饰器模式。比如,对已有的对象进行包装,添加日志记录、性能监控等功能。

public interface Component {
    void operation();
}

public class ConcreteComponent implements Component {
    @Override
    public void operation() {
        // 原始对象的操作
    }
}

public abstract class Decorator implements Component {
    protected Component component;

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

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

public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        // 装饰器的额外操作A
    }
}

public class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        // 装饰器的额外操作B
    }
}

比如在一个咖啡点单系统中,可以根据顾客的选择动态地为咖啡添加不同的调料,而不需要修改咖啡类的代码。示例代码如下:

public interface Coffee {
    double cost(); // 咖啡的价格
}

public class Espresso implements Coffee {
    @Override
    public double cost() {
        return 2.0; // 浓缩咖啡的价格
    }
}

public abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;

    public CoffeeDecorator(Coffee decoratedCoffee) {
        this.decoratedCoffee = decoratedCoffee;
    }

    @Override
    public double cost() {
        return decoratedCoffee.cost();
    }
}

public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }

    @Override
    public double cost() {
        return super.cost() + 0.5; // 添加牛奶的价格
    }
}

public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }

    @Override
    public double cost() {
        return super.cost() + 0.3; // 添加糖的价格
    }
}

public class Main {
    public static void main(String[] args) {
        Coffee espresso = new Espresso();
        System.out.println("Price of espresso: " + espresso.cost());

        Coffee milkCoffee = new MilkDecorator(espresso);
        System.out.println("Price of milk coffee: " + milkCoffee.cost());

        Coffee sugarMilkCoffee = new SugarDecorator(milkCoffee);
        System.out.println("Price of sugar milk coffee: " + sugarMilkCoffee.cost());
    }
}
  • 外观模式(Facade Pattern) 外观模式提供了一个统一的接口,用于访问一组复杂子系统的功能。它封装了子系统的复杂性,提供了一个更简单和易用的接口给客户端使用。
public class SubsystemA {
    public void operationA() {
        // 子系统A的操作
    }
}

public class SubsystemB {
    public void operationB() {
        // 子系统B的操作
    }
}

public class SubsystemC {
    public void operationC() {
        // 子系统C的操作
    }
}

public class Facade {
    private SubsystemA subSystemA;
    private SubsystemB subSystemB;
    private SubsystemC subSystemC;

    public Facade() {
        this.subSystemA = new SubsystemA();
        this.subSystemB = new SubsystemB();
        this.subSystemC = new SubsystemC();
    }

    public void operation() {
        subSystemA.operationA();
        subSystemB.operationB();
        subSystemC.operationC();
    }
}
  • 代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。

代理模式是一种结构型设计模式,它允许一个对象(代理)代表另一个对象进行访问控制。代理模式通常用于控制对其他对象的访问,以提供为其他对象提供一个替代接口或者对其进行保护。代理对象和真实对象之间的关系可以分为静态代理和动态代理两种形式。

在代理模式中,通常涉及以下几个角色:

  1. 抽象主题(Subject):定义了代理对象和真实对象的共同接口,这样代理对象和真实对象就可以对外提供一致的服务。
  2. 真实主题(Real Subject):实际完成业务逻辑的对象,是代理对象所代表的对象。
  3. 代理(Proxy):包含了对真实主题的引用,并且可以对其进行访问控制,提供额外的功能,或者对真实对象进行保护。

在Java中,代理模式常常使用在网络编程、安全控制、日志记录和缓存等场景中,例如RMI(远程方法调用)、Spring AOP(面向切面编程)等都是代理模式的经典应用。以下是一个简单的Java代码示例,演示了代理模式的实现:

// 抽象主题接口
interface Image {
    void display();
}

// 真实主题类
class RealImage implements Image {
    private String fileName;

    public RealImage(String fileName) {
        this.fileName = fileName;
        loadFromDisk(fileName);
    }

    @Override
    public void display() {
        System.out.println("Displaying " + fileName);
    }

    private void loadFromDisk(String fileName) {
        System.out.println("Loading " + fileName + " from disk");
    }
}

// 代理类
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();
    }
}

Image 接口是抽象主题,RealImage 类是真实主题,ProxyImage 类是代理。当客户端调用 display 方法时,代理对象 ProxyImage 会首先检查是否已经创建了真实对象 RealImage,如果没有,则创建并调用真实对象的 display 方法;如果已经存在真实对象,则直接调用真实对象的 display 方法。这样就实现了对真实对象的访问控制。在该示例中,代理模式的应用场景是延迟加载,即真实对象的创建可以延迟到真正需要使用的时候。

总的来说,代理模式可以帮助我们统一对真实对象的访问控制,可以在不改变真实对象的情况下增加额外的功能,例如安全性检测、性能优化、日志记录等。

3️⃣行为型设计模式(常用:观察者、策略、模板方法、命令)

 注:图片来源于网络,版权归属原作者
  • 观察者模式(Observer):定义对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。

在项目中,可以用观察者模式实现事件通知和监听机制。例如,可以创建一个事件管理器类,并将需要监听事件的对象注册为观察者。当事件发生时,通知所有注册的观察者进行相应的处理。

观察者模式定义了一种一对多的依赖关系,当被观察者的状态发生改变时,所有依赖于它的观察者都会得到通知并更新。典型的应用场景是GUI编程中的事件监听和消息通知。

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

public interface Observer {
    void update();
}

public class ConcreteObserver implements Observer {
    @Override
    public void update() {
        // 观察者的具体更新逻辑
    }
}

public interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

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

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

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

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

在需要实现消息订阅和发布功能时,可以使用观察者模式。比如在一个新闻发布系统中,新闻发布者发布新闻时,订阅者会收到通知,并进行相应处理。示例代码如下:

public interface Observer {
    void update(String news); // 定义更新方法
}

public interface Subject {
    void registerObserver(Observer observer); // 注册观察者
    void removeObserver(Observer observer); // 移除观察者
    void notifyObservers(); // 通知观察者
}

public class NewsPublisher implements Subject {
    private List<Observer> 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() {
        for (Observer observer : observers) {
            observer.update("New news is available!");
        }
    }

    public void publishNews() {
        // 发布新闻
        notifyObservers(); // 发送通知
    }
}

public class NewsSubscriber implements Observer {
    @Override
    public void update(String news) {
        System.out.println("Received news: " + news);
        // 处理接收到的新闻
    }
}
  •  策略模式(Strategy):定义一系列算法,把它们封装起来,并且使它们可以互相替换。

策略模式定义了一系列可互换的算法,并使得算法的变化独立于使用它的客户端。通过封装算法,可以在运行时选择不同的算法。示例1:

public interface SortStrategy {
    void sort(int[] data);
}

public class BubbleSortStrategy implements SortStrategy {
    @Override
    public void sort(int[] data) {
        // 冒泡排序的具体实现
    }
}

public class QuickSortStrategy implements SortStrategy {
    @Override
    public void sort(int[] data) {
        // 快速排序的具体实现
    }
}

public class Sorter {
    private SortStrategy strategy;

    public Sorter(SortStrategy strategy) {
        this.strategy = strategy;
    }

    public void sort(int[] data) {
        strategy.sort(data);
    }
}

在项目中需要根据不同的策略进行不同的操作时,可以使用策略模式。比如在一个电商系统中,根据不同的活动使用不同的优惠策略,可以使用策略模式。示例2代码如下:

public interface DiscountStrategy {
    double applyDiscount(double originalPrice); // 应用折扣策略
}

public class RegularCustomerDiscount implements DiscountStrategy {
    @Override
    public double applyDiscount(double originalPrice) {
        return originalPrice * 0.9; // 正常客户打9折
    }
}

public class VIPCustomerDiscount implements DiscountStrategy {
    @Override
    public double applyDiscount(double originalPrice) {
        return originalPrice * 0.8; // VIP客户打8折
    }
}

public class PriceCalculator {
    private DiscountStrategy discountStrategy;

    public PriceCalculator(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public double calculateFinalPrice(double originalPrice) {
        return discountStrategy.applyDiscount(originalPrice);
    }
}
  • 模板方法模式(Template Method):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中实现。

模板方法模式是一种行为型设计模式,它定义了一个算法的框架,并允许子类在不改变该算法结构的情况下重新定义该算法的某些步骤。

以下是一个简单的模板方法模式示例,假设我们有一个制作饮料的类:饮料

public abstract class Beverage {
    // 制作饮料的模板方法
    public final void prepareBeverage() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    // 将水煮沸
    public void boilWater() {
        System.out.println("Boiling water");
    }

    // 泡制饮料
    public abstract void brew();

    // 将饮料倒入杯中
    public void pourInCup() {
        System.out.println("Pouring into cup");
    }

    // 添加调料
    public abstract void addCondiments();
}

现在我们可以创建具体的饮料类,比如咖啡和茶:

public class Coffee extends Beverage {
    @Override
    public void brew() {
        System.out.println("Dripping Coffee through filter");
    }

    @Override
    public void addCondiments() {
        System.out.println("Adding Sugar and Milk");
    }
}

public class Tea extends Beverage {
    @Override
    public void brew() {
        System.out.println("Steeping the tea");
    }

    @Override
    public void addCondiments() {
        System.out.println("Adding Lemon");
    }
}

在这个示例中,Beverage 类定义了一个模板方法 prepareBeverage(),该方法包含了制作饮料的算法框架,并调用了一系列抽象方法 boilWater()、brew()、pourInCup() 和 addCondiments()。具体的饮料类如 Coffee 和 Tea 可以继承 Beverage 并实现这些抽象方法来自定义制作过程。

通过模板方法模式,我们可以将共享的制作流程放在父类中,同时允许子类根据自己的特性来实现具体步骤,从而实现了代码的重用和灵活性。

  • 命令模式(Command Pattern) 命令模式将一个请求封装为一个对象,并提供执行该请求的方法。这样可以让客户端参数化请求,即可以用不同的请求对象进行参数化。
public interface Command {
    void execute();
}

public class ConcreteCommand implements Command {
    private Receiver receiver;

    public ConcreteCommand(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.action();
    }
}

public class Receiver {
    public void action() {
        // 接收者的具体操作
    }
}

public class Invoker {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void executeCommand() {
        command.execute();
    }
}

按照其他的作用范围也可以分为:

 注:图片来源于网络,版权归属原作者
 注:图片来源于网络,版权归属原作者

以上是一些常见的设计模式在Java中的应用示例。设计模式是软件工程师必备的工具之一,通过学习和应用设计模式,可以提高代码的可读性、可维护性和可扩展性,帮助构建高质量的软件系统。

二、其他问答

4️⃣面试中关于设计模式如何考察

(思考该如何回答?在实际项目中如何应用?)

在实际项目开发中,常用和面试经常问的设计模式包括工厂方法模式、单例模式、观察者模式、策略模式、装饰器模式和适配器模式。在面试中,通常会问及如何使用这些设计模式来解决特定的问题,以考察面试者对设计模式的理解和应用能力。

在面试时,可以按照以下结构回答与设计模式相关的问题:

  1. 了解问题: 首先要确保对于面试官提出的问题有充分的理解,明确问题的背景和需求。

  2. 解释设计模式: 对于问及的设计模式,解释设计模式的基本概念和作用,以及在什么场景下常常被使用。

  3. 描述实际场景: 提供一个实际的项目开发或者工程中的场景,说明在这个场景下如何应用该设计模式。可以使用自己曾经经历的项目经验,或者构建一个简单的场景来说明。

  4. 优点和缺点: 讨论该设计模式在具体场景中的优点和缺点,以及为什么选择该设计模式而不是其他设计模式。

  5. 举例说明: 如果可能的话,举出更多实际的例子来说明该设计模式的应用,以及它如何帮助解决了具体问题。

  6. 总结: 结束时对于该设计模式的应用做一个简单的总结,并强调你的理解和应用能力。

在面试中,深入举例说明自己在实际项目中如何应用设计模式,以及对设计模式的理解程度,会给面试官留下良好的印象,展示自己的技术能力和经验。

下面是一些高频且容易被考察的设计模式问题以及问题的答案

  • 解释什么是设计模式?设计模式是什么目的?

    答:设计模式是针对常见软件设计问题提出的可重用解决方案。它的目的是提供一种通用的解决方案,以便在软件开发中用于解决特定类型的问题。   

  • 请列举常用的创建型设计模式?

    答:常用的创建型设计模式包括工厂方法模式、抽象工厂模式、单例模式、建造者模式和原型模式。   

  • 什么是单例模式?请写一个线程安全的单例模式的示例代码。

    答:单例模式是一种保证一个类仅有一个实例,并提供一个全局访问点的设计模式。

示例代码可以是:

public class Singleton {
    private static Singleton instance;    private Singleton() {
    }    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
  • 请列举常用的结构型设计模式?

答:常用的结构型设计模式包括适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式和享元模式。

  • 什么是适配器模式?请写一个适配器模式的示例代码。

答:适配器模式是将一个类的接口转换成客户希望的另外一个接口。示例代码可以是:

public interface MediaPlayer {
    void play(String audioType, String fileName);
}

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

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

    @Override
    public void playMp4(String fileName) {
        // Do nothing
    }
}

public class MediaAdapter implements MediaPlayer {
    AdvancedMediaPlayer advancedMusicPlayer;

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

    @Override
    public void play(String audioType, String fileName) {
        if(audioType.equalsIgnoreCase("vlc")){
            advancedMusicPlayer.playVlc(fileName);
        }
    }
}
  • 请列举常用的行为型设计模式?

答:常用的行为型设计模式包括策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式等。

  • 什么是策略模式?请写一个策略模式的示例代码。

答:策略模式定义了一系列算法,将每个算法封装起来,并使它们可以互相替换。示例代码可以是:

public interface Strategy {
    int doOperation(int num1, int num2);
}

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

public 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 interface Observer {
    void update(String message);
}

public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(String message);
}

public class ConcreteSubject implements Subject {
    private List<Observer> 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(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}
  • 请解释装饰器模式的用途,并写一个装饰器模式的示例代码。

答:装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。示例代码可以是:

public interface Shape {
    void draw();
}

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Shape: Circle");
    }
}

public abstract class ShapeDecorator implements Shape {
    protected Shape decoratedShape;

    public ShapeDecorator(Shape decoratedShape){
        this.decoratedShape = decoratedShape;
    }

    public void draw(){
        decoratedShape.draw();
    }
}

public class RedShapeDecorator extends ShapeDecorator {
    public RedShapeDecorator(Shape decoratedShape) {
        super(decoratedShape);
    }

    @Override
    public void draw() {
        decoratedShape.draw();
        setRedBorder(decoratedShape);
    }

    private void setRedBorder(Shape decoratedShape){
        System.out.println("Border Color: Red");
    }
}
  • 什么是工厂方法模式?请写一个工厂方法模式的示例代码。

答:工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。示例代码可以是:

public interface Shape {
    void draw();
}

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Inside Circle::draw() method.");
    }
}

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Inside Rectangle::draw() method.");
    }
}

public interface ShapeFactory {
    Shape createShape();
}

public class CircleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Circle();
    }
}

public class RectangleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Rectangle();
    }
}
  • 简要介绍一下代理模式,并写一个代理模式的示例代码。

答:代理模式为其他对象提供一种方式来控制对这个对象的访问。示例代码可以是:

public interface Image {
    void display();
}

public class RealImage implements Image {
    private String fileName;

    public RealImage(String fileName) {
        this.fileName = fileName;
    }

    @Override
    public void display() {
        System.out.println("Displaying " + fileName);
    }
}

public 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 abstract class Logger {
    public static int INFO = 1;
    public static int DEBUG = 2;
    public static int ERROR = 3;

    protected int level;

    protected Logger nextLogger;

    public void setNextLogger(Logger nextLogger) {
        this.nextLogger = nextLogger;
    }

    public void logMessage(int level, String message) {
        if (this.level <= level) {
            write(message);
        }
        if (nextLogger != null) {
            nextLogger.logMessage(level, message);
        }
    }

    abstract protected void write(String message);
}

public class ConsoleLogger extends Logger {
    public ConsoleLogger(int level) {
        this.level = level;
    }

    protected void write(String message) {
        System.out.println("Standard Console::Logger: " + message);
    }
}

public class ErrorLogger extends Logger {
    public ErrorLogger(int level) {
        this.level = level;
    }

    protected void write(String message) {
        System.out.println("Error Console::Logger: " + message);
    }
}

public class FileLogger extends Logger {
    public FileLogger(int level) {
        this.level = level;
    }

    protected void write(String message) {
        System.out.println("File::Logger: " + message);
    }
}
  • 何谓模板方法模式?请写一个模板方法模式的示例代码。

答:模板方法模式定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现。示例代码可以是:

public abstract class Game {
    abstract void initialize();
    abstract void startPlay();
    abstract void endPlay();

    public final void play() {
        initialize();
        startPlay();
        endPlay();
    }
}

public 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!");
    }
}

public 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 interface Iterator {
    boolean hasNext();
    Object next();
}

public interface Container {
    Iterator getIterator();
}

public class NameRepository implements Container {
    public String names[] = {"Robert", "John", "Julie", "Lora"};

    @Override
    public Iterator getIterator() {
        return new NameIterator();
    }

    private class NameIterator implements Iterator {
        int index;

        @Override
        public boolean hasNext() {
            return index < names.length;
        }

        @Override
        public Object next() {
            if(this.hasNext()) {
                return names[index++];
            }
            return null;
        }
    }
}


  • 创建型设计模式中的抽象工厂模式的作用是什么?请写一个抽象工厂模式的示例代码。

答:抽象工厂模式提供了一种方式,可以以独立于产品的方式创建一系列相关或依赖对象。示例代码可以是:

public interface Shape {
    void draw();
}

public class RoundedRectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Inside RoundedRectangle::draw() method.");
    }
}

public class RoundedSquare implements Shape {
    @Override
    public void draw() {
        System.out.println("Inside RoundedSquare::draw() method.");
    }
}

public abstract class AbstractFactory {
    abstract Shape getShape(String shapeType);
}

public class RoundedShapeFactory extends AbstractFactory {
    @Override
    public Shape getShape(String shapeType) {
        if(shapeType.equalsIgnoreCase("RECTANGLE")){
            return new RoundedRectangle();
        } else if(shapeType.equalsIgnoreCase("SQUARE")){
            return new RoundedSquare();
        }
        return null;
    }
}

这些问题和示例代码可以帮助面试者巩固对设计模式的理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/248598.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何使用ArcGIS Pro裁剪影像

对影像进行裁剪是一项比较常规的操作&#xff0c;因为到手的影像可能是多种范围&#xff0c;需要根据自己需求进行裁剪&#xff0c;这里为大家介绍一下ArcGIS Pro中裁剪的方法&#xff0c;希望能对你有所帮助。 数据来源 本教程所使用的数据是从水经微图中下载的影像和行政区…

Springboot的火车票订票系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; Springboot的火车票订票系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#…

Spring Boot整合Sharding-JDBC实现数据脱敏

目录 背景ShardingSphere脱敏规则sharding-jdbc数据脱敏数据脱敏配置数据分片 数据脱敏配置 背景 对互联网公司、传统行业来说&#xff0c;数据安全一直是极为重视和敏感的话题。数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形&#xff0c;实现敏感隐私数据的可靠保护…

【Avue】点击新增再点击表单得radio选项出现新表单,且编辑页面关不掉新表单处理方法

一、问题描述 1、点击新增 2、 点击radio选择值 1、点击否得时候没反应 2、点击是得时候出现新表单 2.1、旧代码 {label: 是否危险源,prop: isBigdanger,searchLabelWidth: 120,overHidden: true,span: 24,rules: [{required: true,message: 请选择是否重大危险源,trigger: bl…

Mapreduce小试牛刀(2)--java api

1.同hdfs 的java api,我们首先要在IDE中建立一个maven项目 pom.xml中配置如下&#xff1a; <dependencies><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-mapreduce-client-common</artifactId><version>3.…

磁盘坏道扫描工具 Macrorit Disk Scanner v6.7.0 中文免费版 -供大家学习研究参考

非常方便实用的磁盘坏道修复软件。Wipe Bad Disk功能强大好用&#xff0c;通过特殊的算法来强制将硬盘的坏道删除清空格式化&#xff0c;从而拯救因产生坏道而不敢继续使用的硬盘!要注意的是经过这块软件清空的硬盘数据基本上是不能被恢复的&#xff0c;所以操作前请一定要备份…

武林风云之linux组软raid0

小y可喜欢玩文明系列的游戏了&#xff0c;因为小y也一直喜欢造轮子&#xff0c;属于自己的轮子。 每次小y听到”要向雄鹰一样&#xff0c;定要遨游于天际。”感觉自己给自己打了一针强心剂&#xff0c;要求自己拼搏进取。 众所周知&#xff0c;文明是个原生的linux游戏&#xf…

Linux 系统 yum 安装 jdk1.8

1、首先检查是否存在jdk java -version上图这样就是系统没有找到已经安装的jdk 2.查看jdk版本列表 yum -y list java*执行此命令会显示所有版本 jdk 安装包 3、下载安装jdk 这里安装的是jdk1.8 yum install java-1.8.0-openjdk-devel.x86_64这里输入回车y继续安装 4、再次检…

学习Django从零开始之三

搭建虚拟python环境 搭建开发环境有多种方式&#xff0c;其中包括本地直接安装Python的可执行文件&#xff0c;使用virtualenv&#xff0c;以及使用Anaconda和Miniconda等工具。这些工具在创建Python虚拟环境方面各有特点。具体不同之处感兴趣的同学可以自行查阅相关资料。 简…

docker consul 容器的自动发现与注册

consul相关知识 什么是注册与发现 服务注册与发现是微服务架构中不可或缺的重要组件。起初服务都是单节点的&#xff0c;不保障高可用性&#xff0c;也不考虑服务的压力承载&#xff0c;服务之间调用单纯的通过接口访问。直到后来出现了多个节点的分布式架构&#xff0c;起初的…

大创项目推荐 深度学习 opencv python 实现中国交通标志识别

文章目录 0 前言1 yolov5实现中国交通标志检测2.算法原理2.1 算法简介2.2网络架构2.3 关键代码 3 数据集处理3.1 VOC格式介绍3.2 将中国交通标志检测数据集CCTSDB数据转换成VOC数据格式3.3 手动标注数据集 4 模型训练5 实现效果5.1 视频效果 6 最后 0 前言 &#x1f525; 优质…

通义千问 Qwen-72B-Chat在PAI-DSW的微调推理实践

01 引言 通义千问-72B&#xff08;Qwen-72B&#xff09;是阿里云研发的通义千问大模型系列的720亿参数规模模型。Qwen-72B的预训练数据类型多样、覆盖广泛&#xff0c;包括大量网络文本、专业书籍、代码等。Qwen-72B-Chat是在Qwen-72B的基础上&#xff0c;使用对齐机制打造的…

String类的hashCode()方法源码分析

Object类中的hashCode()方法&#xff1a; 同一个对象&#xff0c;hashCode必须相同&#xff1b;如果两个对象的equals相等&#xff0c;那么hashCode也必须要相等&#xff01;hashCode()方法是native本地方法&#xff0c;是C代码&#xff0c;hashCode的值&#xff0c;不一定是…

高级前端开发工程师

岗位需求 熟练掌握前端主流框架Vue、React、Angular,至少熟练掌控Vue全家桶 文章目录 岗位需求前言一、Vue框架二、React框架三、Angular框架四、什么是Vue全家桶前言 -那就看你表哥的电脑里有没有硬盘 -我不敲键盘 一、Vue框架 Vue(读音为/vjuː/,类似于"view"…

生产环境_Spark处理轨迹中跨越本初子午线的经度列

使用spark处理数据集&#xff0c;解决gis轨迹点在地图上跨本初子午线的问题&#xff0c;这个问题很复杂&#xff0c;先补充一版我写的 import org.apache.spark.{SparkConf, SparkContext} import org.apache.spark.sql.{Row, SparkSession} import org.apache.spark.sql.func…

Unity inspector绘制按钮与Editor下生成与销毁物体的方法 反射 协程 Editor

应美术要求&#xff0c;实现一个在编辑环境下&#xff0c;不运行&#xff0c;可以实例化预制体的脚本 效果如上图所示 1.去实现一个简单的 行、列实例化物体脚本 2.在Inspector下提供按钮 3.将方法暴露出来&#xff08;通过自定义标签实现&#xff09; 需求一 using System.C…

单片机Freertos入门(二)任务的创建、删除

1、串口配置 首先将串口进行配置&#xff0c;后续经常会应用&#xff0c;具体步骤点击&#xff1a;串口配置。 2、任务 创建一个任务&#xff0c;就是开辟一个空间、每个任务中都会有while&#xff08;1&#xff09;死循环。 2.1相关函数 动态创建&#xff1a;xTaskCreate…

PostgreSQL常用命令

数据库版本 :9.6.6 注意 :PostgreSQL中的不同类型的权限有 SELECT,INSERT,UPDATE,DELETE,TRUNCATE,REFERENCES,TRIGGER,CREATE,CONNECT,TEMPORARY,EXECUTE 和 USAGE。 1. 登录PG数据库 以管理员身份 postgres 登陆,然后通过 #psql -U postgres #sudo -i -u postgres …

【强化学习-读书笔记】表格型问题的 Model-Free 方法

参考 Reinforcement Learning, Second Edition An Introduction By Richard S. Sutton and Andrew G. Barto无模型方法 在前面的文章中&#xff0c;我们介绍的是有模型方法&#xff08;Model-Based&#xff09;。在强化学习中&#xff0c;"Model"可以理解为算法…

AcWing 1250. 格子游戏(并查集)

题目链接 活动 - AcWing本课程系统讲解常用算法与数据结构的应用方式与技巧。https://www.acwing.com/problem/content/1252/ 题解 当两个点已经是在同一个连通块中&#xff0c;再连一条边&#xff0c;就围成一个封闭的圈。一般用x * n y的形式将&#xff08;x, y&#xff0…