java基础知识④:设计模式

news2024/11/15 15:45:38

目录

一、设计模式

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;
    }
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

windows下redis 设置开机自启动

1&#xff0c;在redis的目录下执行&#xff08;执行后就作为windows服务了&#xff09; redis-server --service-install redis.windows.conf 2&#xff0c;安装好后需要手动启动redis redis-server --service-start 3&#xff0c;停止服务 redis-server --service-stop

springMVC 学习总结(四) 拦截器及统一异常处理

一.拦截器 1.拦截器与过滤器的区别 拦截器 Interceptor 和 过滤器 Filter类似&#xff0c;主要用于拦截用户请求并作出一定处理操作&#xff0c; 但两则也有不同之处&#xff0c;如过滤器只在Servlet前后起作用&#xff0c;是Servlet规范定义的&#xff0c;是Servlt容器才支…

邮政快递查询,邮政快递单号查询,根据更新量筛选出需要的单号

批量查询邮政快递单号的物流信息&#xff0c;并根据物流更新量将需要的单号筛选出来。 所需工具&#xff1a; 一个【快递批量查询高手】软件 邮政快递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;第一次使用的伙伴记得先注册&…

stm32H库的内部FLASH读写操作与结构体数组数据写入与读取

stm32H库的内部FLASH读写操作与结构体数组数据写入与读取 1.软硬件准备2.关于STM32的Flash的一些说明3.实验结果 参考博主-STM32系列(HAL库)——内部FLASH读写实验 1.软硬件准备 软件&#xff1a;CubeMX、SSCOM&#xff08;串口调试助手&#xff09; 硬件&#xff1a;SMT32F…

SQL进阶理论篇(七):B+树的查询及存储机制

文章目录 简介数据库中的存储结构数据库中的页结构从数据页来看B树的查询过程总结参考文献 简介 我们之前已经了解过数据库的B树索引和Hash索引&#xff0c;这些索引信息以及数据记录都是保存在文件里的&#xff0c;确切的说是存储在页结构中。 本节&#xff0c;从我们将了解…

Agilent安捷伦34972A数据采集仪34908A采集卡

附加功能: 3插槽LXI数据采集单元&#xff0c;带6位数字数字多用表(22位)和8个插件模块可供选择(单独出售) 测量11种不同的输入信号(无外部信号调理)&#xff0c;包括热电偶、RTD和热敏电阻的温度&#xff1b;DC/交流伏特或电流&#xff1b;2线或4线电阻&#xff1b;频率和周期…

FindMy技术用于滑雪板

随着冬季运动的日益普及&#xff0c;滑雪板作为滑雪运动的重要器材&#xff0c;也变得越来越受欢迎。在各大雪场和户外运动场所&#xff0c;人们纷纷挥舞着滑雪板&#xff0c;畅享冬季运动的乐趣。 在滑雪过程中&#xff0c;由于雪场的复杂环境和运动的高速性&#xff0c;很容易…

数据结构之排序

目录 ​ 1.常见的排序算法 2.插入排序 直接插入排序 希尔排序 3.交换排序 冒泡排序 快速排序 hoare版本 挖坑法 前后指针法 非递归实现 4.选择排序 直接选择排序 堆排序 5.归并排序 6.排序总结 一起去&#xff0c;更远的远方 1.常见的排序算法 排序&#xff1a;所…

Linux学习笔记-Ubuntu下ssh服务器连接异常Connection reset

文章目录 一、问题问题现象1.1 连接重置无法访问的的问题1.2 查看服务器连接状态1.3 使用调试模式查看的信息 二、临时解决方法三、从根源解决问题3.1 问题分析3.2 服务器的ssh日志3.3 修改ssh配置禁止root登录3.4 配置允许所有ip访问3.5 修改认证方法 角色&#xff1a;百世经纶…

自动化访客互动:提升网站效益与用户体验的关键优势

在激烈的市场竞争环境中&#xff0c;想抢占市场&#xff0c;获得收益并不容易。每一个订单的完成都要经过一定的销售周期&#xff0c;所以企业可以根据销售周期每个阶段的特点进行优化&#xff0c;留住客户。其中&#xff0c;企业可以在与客户在线互动的过程中&#xff0c;让互…

缓存一致性几种解决方案

文章目录 一、理论知识1、概述2、坏的方案2.1 先写 MySQL&#xff0c;再写 Redis2.2 先写 Redis&#xff0c;再写 MySQL2.3 先删除 Redis&#xff0c;再写 MySQL 3、好的方案3.1 先删除 Redis&#xff0c;再写 MySQL&#xff0c;再删除 Redis3.2 先写 MySQL&#xff0c;再删除 …

离散数学知识点-期末复习

目录 一、利用真值表求主析取范式、主合取范式 1.例题 二、推理证明 1.推理规则 2.例题 三、符号化命题 四、有穷集的计数 1.包含互斥原理 2.例题 ​1.文氏图法 2.包含互斥原理法 五、关系的闭包 1.三种闭包 2.Warshall算法 3.例题 六、等价关系 1.定义 2.…

杰卡德的故事

三个男人分别是杰卡德距离 杰卡德相似系数和杰卡德系数 杰卡德相似系数和杰卡德距离是互为相反数的。 杰卡德系数和杰卡德距离是不是一回事 感觉是一回事

Linux--Docker容器(最新)

这里写目录标题 安装Docker安装指令配置加速器 Docker简介名词解释作用run命令解读 操作常见命令命令的别名 数据卷简介数据卷命令使用 本地目录挂载问题发现问题解决二级目录二级目录 安装Docker 安装指令 如下文档 https://b11et3un53m.feishu.cn/wiki/Rfocw7ctXij2RBkShcu…

TrustGeo代码理解(五)sublayers.py

代码链接:https://github.com/ICDM-UESTC/TrustGeo 一、导入模块 import torch import torch.nn as nn import torch.nn.functional as F 这段代码是一个简单的神经网络的定义,用于深度学习任务。 1、import torch:导入 PyTorch 库,提供张量(tensor)等深度学习操作的…

Day62力扣打卡

打卡记录 统计区间中的整数数目&#xff08;动态开点线段树&#xff09; 链接 class CountIntervals:__slots__ left, right, l, r, cntdef __init__(self, l1, r10 ** 9):self.left self.right Noneself.l, self.r, self.cnt l, r, 0def add(self, l: int, r: int) ->…

Spring cloud - 断路器 Resilience4J

其实文章的标题应该叫 Resilience4J&#xff0c;而不是Spring Cloud Resilience4J&#xff0c;不过由于正在对Spring cloud的一系列组件进行学习&#xff0c;为了统一&#xff0c;就这样吧。 概念区分 首先区分几个概念 Spring cloud 断路器&#xff1a;Spring Cloud的官网对…

Python的数据类型及举例集合、元组、列表之间的转换规则

Python语言有八种数据类型&#xff0c;有数字&#xff08;整数、浮点数、复数&#xff09;、字符串、字典、集合、元组、列表、布尔值、空值&#xff0c;下面我演示八种数据类型及集合、元组、列表三种类型之间的转换规则。 一、数据类型示例 下面我演示了八种数据类型&#…

Git使用rebase和merge区别

Git使用rebase和merge区别 模拟环境使用merge合并使用rebase 模拟环境 本地dev分支中DevTest增加addRole() 远程dev被同事提交增加了createResource() 使用merge合并 使用idea中merge解决冲突后, 推送远程dev后,日志图显示 使用rebase idea中使用功能rebase 解决冲突…

PyQt6 安装Qt Designer

前言&#xff1a;在Python自带的环境下&#xff0c;安装Qt Designer&#xff0c;并在PyCharm中配置designer工具。 在项目开发中&#xff0c;使用Python虚拟环境安装PyQt6-tools时&#xff0c;designer.exe会安装在虚拟环境的目录中&#xff1a;.venv\Lib\site-packages\qt6_a…