当前位置: 首页 > news >正文

设计模式-面试题

摘要:
1、通俗易懂,适合小白
2、仅做面试复习用,部分来源网络,博文免费,知识无价,侵权请联系!

1. 什么是设计模式?

设计模式是在软件开发过程中,针对反复出现的问题所总结归纳出的通用解决方案。它就像是建筑领域里的经典建筑结构,能帮助开发者更高效、更合理地组织代码,提升软件的可维护性、可扩展性和可复用性 。

2. 为什么要使用设计模式?

  • 可维护性:设计模式使代码结构更清晰,模块职责更明确,便于理解和修改代码。

  • 可扩展性:能轻松应对需求变化,在不破坏原有系统结构的前提下添加新功能。

  • 可复用性:模式中的代码结构和逻辑可在不同项目或模块中重复使用,减少重复开发。

3. 设计模式有多少种,都有哪些设计模式?

设计模式一般分为三种类型,共 23 种:

  • 创建型模式(5 种):单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。

  • 结构型模式(7 种):代理模式、适配器模式、装饰器模式、桥接模式、组合模式、外观模式、享元模式。

  • 行为型模式(11 种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式 。

4. 设计模式的六大原则是什么?

  • 单一职责原则(SRP):一个类应该只负责一项职责,避免一个类承担过多功能。

  • 里氏替换原则(LSP):所有引用基类的地方必须能透明地使用其子类对象,子类可扩展父类功能,但不能改变父类原有功能的语义。

  • 依赖倒置原则(DIP):高层模块不应该依赖低层模块,二者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。

  • 接口隔离原则(ISP):客户端不应该依赖它不需要的接口,一个类对另一个类的依赖应该建立在最小的接口上。

  • 迪米特法则(LoD):一个对象应该对其他对象保持最少的了解,降低对象之间的耦合度。

  • 开闭原则(OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改关闭 。

5. 什么是高内聚、低耦合?

  • 高内聚:指一个模块内的各个元素之间联系紧密,完成单一且明确的功能。比如一个用户信息处理模块,只专注于用户信息的增删改查等相关操作,模块内代码围绕这一核心功能紧密协作。

  • 低耦合:模块与模块之间相互依赖程度低,一个模块的修改不会或很少影响其他模块。例如用户模块和订单模块,二者相对独立,用户模块的业务逻辑变化基本不影响订单模块 。

6. 什么是单例模式?

单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供全局访问点。比如在数据库连接管理中,整个应用程序只需一个数据库连接实例,通过单例模式可以保证在任何地方获取到的都是同一个数据库连接对象 。

7. 单例模式中俄汉式和懒汉式有什么区别?

  • 饿汉式:类加载时就创建实例,线程安全。因为在类初始化阶段实例就已创建,不存在多线程并发创建的问题。例如:
public class EagerSingleton {private static final EagerSingleton instance = new EagerSingleton();private EagerSingleton() {}public static EagerSingleton getInstance() {return instance;}}
  • 懒汉式:在第一次调用获取实例方法时才创建实例。但在多线程环境下若不做同步处理会出现多个实例的问题,所以通常需要加锁保证线程安全。比如:
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static synchronized LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}}

8. 单例模式都有哪些应用场景?

  • 日志记录器:整个应用程序只需一个日志记录器实例,用于统一记录日志信息。

  • 配置管理器:管理应用程序的配置信息,保证各处获取的配置一致。

  • 数据库连接池:维护一个数据库连接池实例,供多个模块复用数据库连接 。

9. 什么是代理模式?

代理模式是一种结构型设计模式,为其他对象提供一种代理以控制对这个对象的访问。代理对象和目标对象实现相同接口,客户端通过代理对象间接访问目标对象。比如在网络访问中,代理服务器可以代替客户端去访问目标网站,在访问前可以进行权限检查、缓存处理等操作 。

10. Java 中代理模式如何实现静态代理?

静态代理需要代理类和目标类实现相同接口,在代理类中持有目标类对象,通过构造函数传入。示例代码如下:

// 定义接口interface Subject {void request();}// 目标类class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject handling request");}}// 代理类class Proxy implements Subject {private RealSubject realSubject;public Proxy(RealSubject realSubject) {this.realSubject = realSubject;}@Overridepublic void request() {System.out.println("Proxy pre - processing");realSubject.request();System.out.println("Proxy post - processing");}}

使用时:

RealSubject realSubject = new RealSubject();Proxy proxy = new Proxy(realSubject);proxy.request();

11. Java 中代理模式如何实现动态代理?

Java 动态代理通过 java.lang.reflect.ProxyInvocationHandler 接口实现。步骤如下:

  1. 定义目标接口和目标类。

  2. 实现 InvocationHandler 接口,在 invoke 方法中编写代理逻辑,处理目标方法调用。

  3. 使用 Proxy.newProxyInstance 方法创建代理对象。示例代码:

// 目标接口interface Subject {void request();}// 目标类class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject handling request");}}// 实现InvocationHandlerclass MyInvocationHandler implements InvocationHandler {private Object target;public MyInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object\[] args) throws Throwable {System.out.println("Dynamic proxy pre - processing");Object result = method.invoke(target, args);System.out.println("Dynamic proxy post - processing");return result;}}// 创建动态代理对象Subject realSubject = new RealSubject();Subject proxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),realSubject.getClass().getInterfaces(),new MyInvocationHandler(realSubject));proxy.request();

12. Java 中什么是解释器模式?

解释器模式是一种行为型设计模式,给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。在 Java 中,比如表达式解析场景,通过定义文法规则和解释器来解析并计算表达式的值 。

13. Java 中如何实现解释器模式?

  1. 定义抽象表达式类,声明解释方法 interpret

  2. 实现终结符表达式类和非终结符表达式类,分别对应文法中的终结符和非终结符,实现 interpret 方法。

  3. 客户端调用解释器进行表达式解释。示例代码(简单算术表达式解释):

// 抽象表达式abstract class Expression {public abstract int interpret();}// 终结符表达式(数字)class NumberExpression extends Expression {private int number;public NumberExpression(int number) {this.number = number;}@Overridepublic int interpret() {return number;}}// 非终结符表达式(加法)class AddExpression extends Expression {private Expression left;private Expression right;public AddExpression(Expression left, Expression right) {this.left = left;this.right = right;}@Overridepublic int interpret() {return left.interpret() + right.interpret();}}// 客户端调用Expression expression = new AddExpression(new NumberExpression(3), new NumberExpression(4));int result = expression.interpret();System.out.println("Result: " + result);

14. Java 中什么是替换法则(LSP)?

里氏替换原则(LSP)规定,所有引用基类的地方必须能透明地使用其子类对象。子类必须能够完全替代父类,且在替换后程序的正确性和行为不能被改变。子类可以扩展父类功能,但不能改变父类方法的前置条件和后置条件 。

15. Java 中为什么不允许从静态方法中访问非静态变量?

静态方法属于类本身,在类加载时就存在,不依赖于类的实例。而非静态变量属于类的实例,只有在创建对象后才存在。如果允许静态方法访问非静态变量,就会出现静态方法执行时非静态变量可能还未初始化的情况,导致逻辑错误和内存问题 。

16. 微服务架构的六种常用设计模式是什么?

  • 服务发现模式:解决微服务实例的注册与发现问题,如使用 Eureka、Consul 等组件,让客户端能找到服务实例的地址。

  • 断路器模式:防止服务调用中出现级联故障,当目标服务调用失败率达到一定阈值时,断路器自动断开,不再调用目标服务,避免消耗过多资源。

  • 负载均衡模式:将请求均匀分配到多个服务实例上,提高系统的可用性和性能,常见的有 Nginx 负载均衡、Ribbon 负载均衡等。

  • API 网关模式:作为微服务的统一入口,负责请求路由、认证授权、流量控制等,对客户端隐藏内部微服务细节 。

  • 事件溯源模式:通过记录系统所有状态变化的事件,按顺序回放事件来重建系统状态,常用于需要追踪历史操作和审计的场景。

  • 命令查询职责分离(CQRS)模式:将读操作(查询)和写操作(命令)分离,分别设计不同的接口和逻辑,提高系统的可扩展性和性能 。

17. Java 中单例模式有什么优缺点?

  • 优点

    • 资源利用率高:避免频繁创建和销毁对象,像数据库连接单例,减少连接创建开销。

    • 全局访问方便:提供全局唯一访问点,便于在不同模块获取同一实例。

  • 缺点

    • 扩展性差:不利于继承和扩展,修改单例类可能影响整个应用。

    • 不利于测试:单例实例可能在测试前就已创建,难以进行单元测试隔离 。

    • 线程安全问题(懒汉式):如果不处理好,懒汉式在多线程环境下可能创建多个实例 。

18. Java 中单例模式使用时有哪些注意事项?

  • 线程安全:如果是懒汉式单例,要确保在多线程环境下的线程安全,可通过同步锁或静态内部类等方式实现。

  • 防止反射攻击:重写单例类的构造函数,防止通过反射创建多个实例。

  • 序列化和反序列化:如果单例类实现了 Serializable 接口,要处理好序列化和反序列化过程,保证反序列化后还是同一个实例 。

19. Java 中单例模式如何防止反射漏洞攻击?

在单例类的构造函数中添加判断逻辑,当发现已经创建过实例时,抛出异常阻止通过反射创建新实例。示例代码:

public class Singleton {private static Singleton instance;private Singleton() {if (instance != null) {throw new RuntimeException("Singleton instance already exists");}}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}

20. 什么是工厂模式?

工厂模式是一种创建型设计模式,它提供了一种创建对象的方式,将对象的创建和使用分离。通过工厂类来负责创建对象,调用者只需要关心如何使用对象,而不需要了解对象的创建细节 。

21. Java 中工厂模式有什么优势?

  • 解耦创建和使用:使代码的依赖关系更清晰,创建对象的逻辑集中在工厂类,使用方无需知道创建细节。

  • 提高可维护性和可扩展性:如果创建对象的逻辑发生变化,只需要修改工厂类,不影响使用对象的其他代码。新增对象类型时,只需在工厂类中添加相应创建逻辑 。

  • 便于代码复用:工厂类可以被多个地方复用,提高代码复用率 。

22. 说说你理解的 Spring 中工厂模式?

在 Spring 框架中,工厂模式广泛应用于 Bean 的创建。比如 BeanFactory 就是一个工厂,它负责根据配置信息创建和管理 Bean 实例。开发者通过配置文件或注解定义 Bean 的信息,BeanFactory 按照这些信息来创建 Bean,将对象的创建和使用分离,同时 Spring 还提供了 FactoryBean 接口,允许开发者自定义 Bean 的创建逻辑,进一步增强了创建对象的灵活性 。

23. 为什么 Spring IOC 要使用工厂模式创建 Bean?

  • 实现解耦:将 Bean 的创建逻辑从使用它的代码中分离出来,降低组件之间的耦合度。例如一个业务组件依赖其他服务组件,通过 IOC 容器(基于工厂模式)创建和注入服务组件,业务组件无需关心服务组件的创建细节。

  • 便于管理和配置:IOC 容器可以统一管理 Bean 的生命周期、作用域等,通过配置文件或注解就能灵活配置 Bean 的创建方式、依赖关系等,方便应用程序的维护和扩展 。

  • 支持依赖注入:工厂模式为依赖注入提供了基础,能方便地将依赖的对象注入到目标对象中,实现对象之间的协作 。

24. Java 中工厂模式分为哪几大类?

Java 中工厂模式主要分为三类:

  • 简单工厂模式:简单工厂不是一种标准的设计模式,它是工厂方法模式的简化。有一个工厂类,根据传入的参数决定创建哪个具体产品类的实例。

  • 工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

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

25. Java 中什么是简单工厂模式?

简单工厂模式有一个工厂类,它根据传入的参数来决定创建哪个具体产品类的实例。工厂类有一个创建对象的方法,该方法通常是静态的,通过条件判断(如 switch - case 语句)根据不同参数创建不同产品对象。例如创建不同类型的图形对象:

// 产品接口interface Shape {void draw();}// 具体产品类:圆形class Circle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a circle");}}// 具体产品类:矩形class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a rectangle");}}// 简单工厂类class ShapeFactory {public static Shape createShape(String type) {if ("circle".equalsIgnoreCase(type)) {return new Circle();} else if ("rectangle".equalsIgnoreCase(type)) {return new Rectangle();}return null;}}

使用时:

Shape circle = ShapeFactory.createShape("circle");circle.draw();

26. Java 中简单工厂模式有什么优缺点?

  • 优点

    • 实现简单:工厂类集中了对象创建逻辑,使用方只需传入参数就能获取对象,代码简洁易懂。

    • 解耦创建和使用:将对象创建和使用分离,提高了代码的可维护性。

  • 缺点

    • 不符合开闭原则:当需要新增产品类型时,需要修改工厂类的创建逻辑(如添加 switch - case 分支),违反了开闭原则。

    • 职责过重:工厂类承担了所有对象的创建逻辑,当产品类型过多时,工厂类会变得复杂难以维护 。

27. Java 中什么是工厂方法模式?

工厂方法模式定义一个用于创建对象的接口(抽象工厂方法),让子类决定实例化哪一个类。抽象工厂类声明抽象的工厂方法,具体工厂子类实现该方法来创建具体产品对象。比如:

// 产品接口interface Product {void operation();}// 具体产品类Aclass ConcreteProductA implements Product {@Overridepublic void operation() {System.out.println("ConcreteProductA operation");}}// 具体产品类Bclass ConcreteProductB implements Product {@Overridepublic void operation() {System.out.println("

51. Java 中什么是策略模式?

策略模式是一种行为型设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。在 Java 中,通常是定义一个策略接口,不同的具体策略类实现该接口,从而实现不同的算法逻辑。这样做可以让使用算法的客户端在运行时动态选择不同的策略,而无需修改客户端代码本身。

52. Java 中策略模式有什么应用场景?

  • 电商促销:在电商系统中,不同的促销活动(如满减、打折、赠品等)可以用策略模式实现。系统根据不同的活动规则选择对应的促销策略,方便活动的添加、修改和替换。

  • 支付方式:支付模块中,多种支付方式(如微信支付、支付宝支付、银行卡支付等)可以分别封装成不同策略,客户端根据用户选择调用相应支付策略。

  • 排序算法:在需要进行排序的场景中,不同的排序算法(冒泡排序、快速排序、归并排序等)可以实现为策略,根据实际需求(数据规模、数据特点等)选择合适的排序策略。

53. Java 中策略模式有什么优缺点?

  • 优点

    • 可维护性和可扩展性高:每个策略算法独立封装,新增或修改算法只需在对应的策略类中操作,不影响其他部分。

    • 复用性好:具体策略类可以在不同场景下被复用。

    • 符合开闭原则:可以在不修改原有代码的情况下,添加新的策略。

  • 缺点

    • 策略类数量可能过多:当算法较多时,会产生大量的策略类,增加代码管理难度。

    • 客户端需要了解策略细节:客户端需要知道有哪些策略可供选择,增加了使用成本。

54. Java 中如何实现策略模式?

  1. 定义策略接口,声明算法方法。例如:
interface Strategy {int execute(int num1, int num2);}
  1. 实现具体策略类。比如加法策略和乘法策略:
class AdditionStrategy implements Strategy {@Overridepublic int execute(int num1, int num2) {return num1 + num2;}}class MultiplicationStrategy implements Strategy {@Overridepublic int execute(int num1, int num2) {return num1 \* num2;}}
  1. 创建上下文类,持有策略对象,并提供设置策略和执行策略的方法:
class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public void setStrategy(Strategy strategy) {this.strategy = strategy;}public int executeStrategy(int num1, int num2) {return strategy.execute(num1, num2);}}
  1. 客户端使用:
Context context = new Context(new AdditionStrategy());int result = context.executeStrategy(3, 4);System.out.println(result);context.setStrategy(new MultiplicationStrategy());result = context.executeStrategy(3, 4);System.out.println(result);

55. Java 中什么是观察者模式?

观察者模式是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖它的对象(观察者)都会得到通知并自动更新。在 Java 中,被观察者通常维护一个观察者列表,当自身状态改变时,遍历列表通知所有观察者。

56. Java 中实现观察者模式有哪两种方式?

  • **基于 JDK 内置的 java.util.Observer 和 **java.util.ObservableObservable 类是被观察者的基类,它提供了添加、删除观察者以及通知观察者的方法。Observer 接口是观察者需要实现的接口,其中 update 方法用于接收被观察者的通知并进行处理。

  • 自定义实现:不依赖 JDK 内置类,自己定义被观察者接口和实现类、观察者接口和实现类。被观察者接口中定义注册、注销观察者以及通知观察者的方法,观察者接口定义接收通知的方法。

57. Java 中观察者模式有什么应用场景?

  • 事件监听:在图形界面编程中,按钮点击、窗口关闭等事件可以用观察者模式实现。组件作为被观察者,监听器作为观察者,当组件状态改变(如按钮被点击)时通知监听器。

  • 消息推送:消息中心作为被观察者,订阅者作为观察者。当有新消息产生时,消息中心通知所有订阅者。

  • 股市行情系统:股票价格作为被观察者,股民客户端作为观察者。当股票价格变动时,通知股民客户端更新行情。

58. Java 中如何实现观察者模式?

基于 JDK 内置的实现方式

  1. 被观察者继承 Observable 类:
import java.util.Observable;class StockPrice extends Observable {private double price;public double getPrice() {return price;}public void setPrice(double price) {this.price = price;setChanged();notifyObservers(price);}}
  1. 观察者实现 Observer 接口:
import java.util.Observable;import java.util.Observer;class Investor implements Observer {@Overridepublic void update(Observable o, Object arg) {if (o instanceof StockPrice) {double newPrice = (double) arg;System.out.println("Stock price updated to: " + newPrice);}}}
  1. 客户端使用:
StockPrice stockPrice = new StockPrice();Investor investor = new Investor();stockPrice.addObserver(investor);stockPrice.setPrice(100.0);

自定义实现方式

  1. 定义被观察者接口:
interface Subject {void registerObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers(Object arg);}
  1. 实现被观察者类:
class WeatherStation implements Subject {private java.util.ArrayList\<Observer> observers = new java.util.ArrayList<>();private String weather;@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers(Object arg) {for (Observer observer : observers) {observer.update(arg);}}public void setWeather(String weather) {this.weather = weather;notifyObservers(weather);}}
  1. 定义观察者接口:
interface Observer {void update(Object arg);}
  1. 实现观察者类:
class Citizen implements Observer {@Overridepublic void update(Object arg) {if (arg instanceof String) {String weather = (String) arg;System.out.println("Weather updated: " + weather);}}}
  1. 客户端使用:
WeatherStation weatherStation = new WeatherStation();Citizen citizen = new Citizen();weatherStation.registerObserver(citizen);weatherStation.setWeather("Sunny");

59. Java 中解释器模式有什么优点?

  • 可扩展性好:如果需要支持新的文法规则,只需要新增对应的终结符或非终结符表达式类,符合开闭原则。

  • 语法分析和解释分离:将语言的语法定义和解释执行过程分离,使得代码结构清晰,便于理解和维护。

  • 重用性高:表达式类可以在不同的解释场景中复用,只要符合相同的文法规则。

60. Java 中什么是适配器模式?

适配器模式是一种结构型设计模式,它将一个类的接口转换成客户希望的另一个接口,使原本由于接口不兼容而不能一起工作的那些类可以一起工作。在 Java 中,通常有类适配器和对象适配器两种实现方式,分别通过继承和组合的方式来实现接口转换。

61. Java 中适配器模式有什么应用场景?

  • 第三方库整合:当引入第三方库时,如果第三方库的接口与现有系统接口不兼容,可使用适配器模式进行适配。比如一个支付系统要接入新的支付渠道,该渠道接口与现有系统接口不同,通过适配器模式可让新渠道融入现有系统。

  • 旧系统升级:在对旧系统进行升级改造时,不改变旧系统代码的情况下,使用适配器模式适配新的接口要求,使旧系统能与新系统协同工作。

  • 不同数据库操作:不同数据库的操作接口可能不同,使用适配器模式可以将不同数据库的操作接口适配成统一的操作接口,方便上层应用调用。

62. Java 中适配器模式有什么优缺点?

  • 优点

    • 提高兼容性:解决了不兼容接口之间的问题,使原本不能协同工作的类可以一起工作。

    • 增强可维护性和可扩展性:将适配逻辑封装在适配器类中,不影响原有类的代码,后续如果接口变化,只需修改适配器类。

    • 符合开闭原则:在不修改原有代码的基础上,通过添加适配器类实现功能扩展。

  • 缺点

    • 增加代码复杂度:引入了额外的适配器类,使代码结构变得复杂,增加了理解和维护成本。

    • 过多使用可能导致混乱:如果系统中大量使用适配器模式,会使系统的接口关系变得混乱,难以理清。

63. Java 中实现适配器模式有几种方式?

  • 类适配器:通过继承需要适配的类,同时实现目标接口来完成适配。它利用了继承的特性,在 Java 中一个类只能继承一个父类,这是类适配器的限制之一。

  • 对象适配器:通过在适配器类中组合一个被适配类的对象,然后实现目标接口,在接口方法实现中调用被适配类对象的方法,实现接口转换。对象适配器更符合组合优于继承的原则,使用更为灵活。

64. Java 中如何实现类的适配器模式?

假设存在一个被适配类 Adaptee ,它有一个方法 specificRequest ,目标接口 Target 有一个方法 request ,实现类适配器如下:

// 被适配类class Adaptee {public void specificRequest() {System.out.println("Adaptee specific request");}}// 目标接口interface Target {void request();}// 类适配器class ClassAdapter extends Adaptee implements Target {@Overridepublic void request() {specificRequest();}}

客户端使用:

Target adapter = new ClassAdapter();adapter.request();

65. Java 中如何实现对象的适配器模式?

还是以上面的 AdapteeTarget 为例,实现对象适配器:

// 被适配类class Adaptee {public void specificRequest() {System.out.println("Adaptee specific request");}}// 目标接口interface Target {void request();}// 对象适配器class ObjectAdapter implements Target {private Adaptee adaptee;public ObjectAdapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specificRequest();}}

客户端使用:

Adaptee adaptee = new Adaptee();Target adapter = new ObjectAdapter(adaptee);adapter.request();

66. Java 中什么是装饰模式?

装饰模式是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。在 Java 中,通常是定义一个抽象组件类,具体组件类实现该抽象类,装饰类也继承或实现该抽象组件类,并且在装饰类中持有一个具体组件对象,通过调用具体组件对象的方法并添加额外逻辑来实现功能增强。

67. 装饰模式和适配器模式有什么区别?

  • 目的不同:装饰模式主要是为了增强对象的功能,在不改变对象接口的前提下动态添加功能;而适配器模式是为了让不兼容的接口能够协同工作,重点在于接口转换。

  • 结构不同:装饰模式中装饰类和被装饰类通常有共同的抽象基类或接口;适配器模式中适配器类和被适配类没有必然的继承或接口实现关系,适配器类主要是为了适配接口。

  • 使用场景不同:当需要在运行时动态地给对象添加功能时,使用装饰模式;当需要整合不同接口的类时,使用适配器模式。

68. 装饰模式和代理模式有什么区别?

  • 目的不同:装饰模式侧重于增强对象功能,在原有功能基础上添加新功能;代理模式主要是控制对目标对象的访问,比如权限控制、延迟加载等。

  • 对客户端的透明性不同:装饰模式对客户端透明,客户端并不知道自己调用的是装饰后的对象还是原始对象;代理模式客户端知道自己使用的是代理对象。

  • 功能扩展方式不同:装饰模式通过层层嵌套装饰类来逐步增强功能;代理模式中代理类通常是集中管理对目标对象的访问控制逻辑。

69. Java 中如何实现装饰模式?

  1. 定义抽象组件:
abstract class Beverage {protected String description = "Unknown Beverage";public String getDescription() {return description;}public abstract double cost();}
  1. 定义具体组件:
class Coffee extends Beverage {public Coffee() {description = "Coffee"}@Overridepublic double cost() {return 1.0;}}
  1. 定义抽象装饰类,继承抽象组件类:
abstract class CondimentDecorator extends Beverage {public abstract String getDescription();}
  1. 定义具体装饰类:
class Milk extends CondimentDecorator {private Beverage beverage;public Milk(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ", Milk";}@Overridepublic double cost() {return 0.5 + beverage.cost();}
}
  1. 客户端使用:
Beverage coffee = new Coffee();coffee = new Milk(coffee);System.out.println(coffee.getDescription() + " costs \$" + coffee.cost());

70. Java 中装饰模式有什么优缺点?

  • 优点

    • 灵活性高:可以在运行时动态地添加或去除功能,通过组合不同的装饰类来满足不同的需求。

    • 符合开闭原则:在不修改原有类代码的基础上,通过新增装饰类来扩展功能。

    • 可维护性好:各个装饰类的功能单一,便于理解和维护,且功能的添加和修改都集中在装饰类中。

  • 缺点

    • 多层装饰可能导致复杂度增加:当装饰层次过多时,代码的可读性和调试难度会增加,难以理清对象的实际功能组合情况。

    • 增加类的数量:每一个具体的装饰功能都需要一个装饰类,会导致类的数量增多,增加代码管理成本。

71. Java 中装饰模式有什么应用场景?

  • 图形界面组件:在 Swing 或 JavaFX 中,为组件添加边框、背景色、提示信息等功能,可以使用装饰模式。例如给按钮添加提示信息装饰,给文本框添加边框装饰等。

  • IO 流处理:Java 的 IO 流中广泛使用了装饰模式,如 BufferedInputStream 可以装饰 InputStream ,为其添加缓冲功能;DataInputStream 可以装饰 InputStream ,为其添加读取基本数据类型的功能。

  • 游戏角色属性增强:在游戏开发中,给游戏角色动态添加属性(如攻击力增强、防御力增强等),可以通过装饰模式实现。

72. 抽象工厂模式和原型模式有什么区别?

  • 创建方式不同:抽象工厂模式通过工厂类创建一系列相关或相互依赖的对象,通常是根据不同的产品族来创建对象;原型模式是通过复制已有的对象实例来创建新对象,通过实现 Cloneable 接口并覆盖 clone 方法来实现对象克隆。

  • 应用场景不同:抽象工厂模式适用于创建一系列相关对象的场景,比如创建不同操作系统下的图形界面组件(按钮、文本框等);原型模式适用于创建重复对象且对象创建成本较高的场景,如创建大量相似的游戏角色。

  • 依赖关系不同:抽象工厂模式中工厂类和产品类之间存在依赖关系,工厂类负责创建产品类对象;原型模式中主要是对象自身的复制,不涉及复杂的工厂类与产品类的依赖关系。

相关文章:

设计模式-面试题

摘要&#xff1a; 1、通俗易懂&#xff0c;适合小白 2、仅做面试复习用&#xff0c;部分来源网络&#xff0c;博文免费&#xff0c;知识无价&#xff0c;侵权请联系&#xff01; 1. 什么是设计模式&#xff1f; 设计模式是在软件开发过程中&#xff0c;针对反复出现的问题所…...

upload-labs靶场通关详解:第11关

一、分析源代码 $is_upload false; $msg null; if (isset($_POST[submit])) {if (file_exists(UPLOAD_PATH)) {$deny_ext array("php","php5","php4","php3","php2","html","htm","phtml"…...

excel:时间戳格式与日期格式的互转

13位时间戳转日期时间&#xff08;毫秒&#xff09; 假设A2单元格内容为13位的时间戳&#xff0c;再选中B2单元格&#xff0c;在公式框中输入 TEXT((A2/10008*3600)/8640070*36519,"yyyy/mm/dd hh:mm:ss.000")接下来&#xff0c;选中B2单元格&#xff0c;下拉应用公…...

嵌套式向量中断控制器(NVIC)

1.概述 2. NVIC 的中断处理机制 3. NVIC 中断管理机制 1.概述 中断控制器是ARMv7-M 异常模型的核心组成部分。该中断控制器的运行遵循 ARM 通用中断控制器(GIC)规范,该规范也适用于其他 ARMv7 架构配置和其他处理器架构。 ARMv7-M 的 NVIC(嵌套向量中断控制器)架构支持最…...

2025.05.19【Barplot】柱状图的多样性绘制

Custom color A few examples showing how to custom barplot color. Horizontal barchart It makes sense to make your barchart horizontal: group labels are now much easier to read 文章目录 Custom colorHorizontal barchart 探索Barplot的奥秘Barplot基础什么是Barp…...

MongoDB的管道聚合

管道聚合可以实现很多数据处理和统计功能&#xff0c;并且随着不断的更新&#xff0c;其功能也越来越丰富。代表着NoSQL数据库的一种发展趋势。 管道聚合通过aggregate语句实现&#xff0c;支持多种匹配、处理、输出方式。 其语法是&#xff1a; db.<collection>.aggr…...

基于 STM32 的自动温度巡检小车控制系统设计与实现

一、引言 在工业监控、仓储管理及环境监测等场景中,自动温度巡检系统具有重要应用价值。本文设计一种基于 STM32 单片机的自动温度巡检小车,通过集成温度采集、路径规划及数据处理功能,实现对目标区域的实时温度监测与异常报警,为智能化环境监控提供低成本解决方案。 二、…...

怎么利用JS根据坐标判断构成单个多边形是否合法

怎么利用JS根据坐标判断构成单个多边形是否合法 引言 在GIS(地理信息系统)、游戏开发、计算机图形学等领域,判断一组坐标点能否构成合法的简单多边形(Simple Polygon)是一个常见需求。合法多边形需要满足几何学上的基本规则,本文将详细介绍如何使用JavaScript实现这一判…...

20. 自动化测试框架开发之Excel配置文件的IO开发

20.自动化测试框架开发之Excel配置文件的IO开发 一、核心架构解析 1.1 类继承体系 class File: # 文件基类# 基础文件验证和路径管理class ExcelReader(File): # Excel读取器# 实现Excel数据解析逻辑1.2 版本依赖说明 # 必须安装1.2.0版本&#xff08;支持xlsx格式&#…...

高校快递物流管理系统设计与实现(SpringBoot+MySQL)

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…...

python-leetcode 67.寻找两个正序数组中的中位数

题目&#xff1a; 给定两个大小分别为m和n的正序&#xff08;从小到大&#xff09;数组nums1和nums2。请找出并返回这两个正序数组的中位数。 通过双指针和二分查找的思想&#xff0c;找到两个有序数组的中位数。 1.初始化和基本情况处理 首先获取两个个数组的长度m和n,计算…...

Python 实现图片浏览和选择工具

实现将截图预览&#xff0c;并按照顺序加入一个pdf文件中&#xff0c;实现照片管理尤其对于喜欢看教程截图做笔记的网友们。 C:\pythoncode\new\python-image-pdf-processor.py 界面展示 &#x1f9f1; 一、核心结构概述 主类 ImageViewer(wx.Frame) 是主窗口类&#xff0c;…...

V4L2应用程序开发-01数据采集流程

1 数据采集流程 可以参考这些文件&#xff1a; mjpg-streamer\mjpg-streamer-experimental\plugins\input_control\input_uvc.c video2lcd\video\v4l2.c Video for Linux two(Video4Linux2)简称V4L2&#xff0c;是V4L的改进版。V4L2支持三种方式来采集图像&#xff1a;内存…...

TDengine 2025年产品路线图

TDengine OSS 之 2025 年年度路线图如下表所示。 季度功能2025Q1 虚拟表查询能力&#xff1a;REGEXP、GREATEST、LEAST、CAST 函数支持判断表达式、单行选择函数的其他列值、INTERP 支持插值时间范围存储能力&#xff1a;支持将查询结果写入超级表、超级表支持 KEEP 参数、STM…...

Unreal 从入门到精通之SceneCaptureComponent2D实现UI层3D物体360°预览

文章目录 前言SceneCaptureComponent2D实现步骤新建渲染目标新建材质UI控件激活3DPreview鼠标拖动旋转模型最后前言 我们在(电商展示/角色预览/装备查看)等应用场景中,经常会看到这种3D展示的页面。 即使用相机捕获一个3D的模型的视图,然后把这个视图显示在一个UI画布上,…...

windows服务器部署jenkins工具

sjenkins作为一款构建发布工具&#xff0c;极大的简化了大家项目部署发布流程。jenkins通常是部署在linux服务上&#xff0c;今天给大家分享的是windows服务器上如何搭建jenkins发布工具。 1.首先第一步还是看windows安装docker 这篇文章哈&#xff0c;当然也可以不采用docker…...

Java—— File详解

说明 File对象就表示一个路径&#xff0c;可以是文件的路径、也可以是文件夹的路径 这个路径可以是存在的&#xff0c;也允许是不存在的 获取File对象 方法名称说明public File(String pathname)根据文件路径创建文件对象public File(String parent,String child)根据父路径名…...

「NameCraft · 幻想命名器」开发记:我和 CodeBuddy 的一次奇幻共创之旅

起心动念&#xff1a;我想做一个不一样的名字生成器 最近我有一个脑洞&#xff1a;能不能做一个风格化强烈的名字生成器&#xff1f;不要那种平平无奇的「小明、小红」类型&#xff0c;而是支持「幻想风」「武侠感」「赛博感」的那种&#xff0c;最好还有高颜值的 UI&#xff…...

03 接口自动化-精通Postman之接口鉴权,接口Mock,接口加解密以及接口签名Sign

文章目录 一、接口鉴权&#xff08;鉴定是否有访问接口的权限&#xff09;1、cookie&#xff0c;session&#xff0c;token鉴权。2、Postman的鉴权方式 二、接口Mock Sersver三、接口的加解密四、接口签名sign&#xff08;接口鉴权的一种&#xff09;1.什么是接口签名&#xff…...

深入浅出IIC协议 -- 第二篇:FPGA数字接口设计方法论

第二篇&#xff1a;FPGA数字接口设计方法论 副标题 &#xff1a;从状态机到跨时钟域——打造工业级I2C控制器的设计密码 1. 状态机设计黄金法则 1.1 状态机类型抉择 Mealy与Moore对比实验 &#xff1a; 类型输出依赖时序特性I2C适用场景Moore仅当前状态延迟稳定协议主状态控…...

20250519使用TF卡将NanoPi NEO core开发板刷机为Ubuntu core22.04.3系统完成之后执行poweroff自动关机

1、h3-sd-friendlycore-xenial-4.14-armhf-20210618.img.gz 在WIN10下使用7-ZIP解压缩/ubuntu20.04下使用tar 2、Win32DiskImager.exe 写如32GB的TF卡。【以管理员身份运行】 3、TF卡如果已经做过会有3个磁盘分区&#xff0c;可以使用SD Card Formatter/SDCardFormatterv5_WinE…...

什么是USB的EHCI和OHCI

USB的EHCI和OHCI是两种不同的主机控制器接口标准&#xff0c;用于规范计算机如何通过硬件和软件与USB设备通信。它们分别对应不同的USB协议版本和设备类型&#xff0c;以下是详细解析&#xff1a; 1. OHCI&#xff08;Open Host Controller Interface&#xff09; • 定位&…...

【2025最新版】Origin安装教程 - 超详细Origin2024中文版图文教程(保姆级附带Origin安装包)

文章目录 前言Origin安装前的必要准备Origin安装包获取Origin安装图文步骤第一步&#xff1a;解压安装包第二步&#xff1a;启动安装程序第三步&#xff1a;安装向导操作第四步&#xff1a;填写注册信息第五步&#xff1a;选择安装位置第六步&#xff1a;功能选择与安装第七步&…...

【网络编程】十二、两万字详解 IP协议

文章目录 Ⅰ. 基本概念1、网络层解决的问题2、保证数据可靠的从一台主机送到另一台主机的前提3、路径选择4、主机和路由器的区别 Ⅱ. IP协议格式IP如何将报头与有效载荷进行分离&#xff1f;IP如何决定将有效载荷交付给上层的哪一个协议&#xff1f;理解socket编程 Ⅲ. 分片与组…...

【机器学习】线性回归和损失函数

线性回归 1.什么是线性回归&#xff1f; 线性回归指的就是将一些输入项乘以相应的权重系数&#xff0c;然后相加得到输出结果。线性回归是机器学习中一种有监督学习的算法,回归问题主要研究的是因变量与一个或多个自变量之间的关系。 在学习线性回归知识之前&#xff0c;我们…...

ip与mac-数据包传输过程学习

你管这破玩意叫网络&#xff1f; 内容来源于飞天闪客&#xff0c;以前没有学习过网络的相关基础知识&#xff0c;只会去瞎设置&#xff0c;现在终于是弄明白了。 多台电脑之间想要通信&#xff0c;可以直接通过一条网线进行连接。但是随着网线的增加&#xff0c;这个就会比较…...

【Qwen开源】WorldPM: 扩展人类偏好建模

受语言建模中的缩放定律启发&#xff0c;该定律展示了测试损失如何随着模型和数据集的规模呈幂律关系扩展&#xff0c;我们发现类似的定律也存在于偏好建模中。我们提出了世界偏好建模&#xff08;WorldPM&#xff09;来强调这种扩展潜力&#xff0c;其中世界偏好体现了人类偏好…...

如何设计一个二级缓存(Redis+Caffeine)架构?Redis 6.0多线程模型如何工作?

一、二级缓存&#xff08;RedisCaffeine&#xff09;架构设计 1. 设计目标 通过「本地缓存&#xff08;Caffeine&#xff09; 分布式缓存&#xff08;Redis&#xff09;」的分层结构&#xff0c;实现&#xff1a; 低延迟&#xff1a;热点数据本地缓存&#xff08;内存级访问…...

MYSQL8.0常用窗口函数

MYSQL8.0常用窗口函数 一、窗口函数的基本概念 窗口函数&#xff0c;顾名思义&#xff0c;就是在查询结果集中定义一个“窗口”&#xff0c;在这个窗口内进行数据的计算和分析。与普通聚合函数不同&#xff0c;普通聚合函数会将结果集分组并返回每组的单一汇总值&#xff0c;…...

【Pandas】pandas DataFrame pct_change

Pandas2.2 DataFrame Computations descriptive stats 方法描述DataFrame.abs()用于返回 DataFrame 中每个元素的绝对值DataFrame.all([axis, bool_only, skipna])用于判断 DataFrame 中是否所有元素在指定轴上都为 TrueDataFrame.any(*[, axis, bool_only, skipna])用于判断…...

Model 复现系列(一)OpenVLA

这个系列用来记录一些开源模型在本地部署或测试时遇到的一些坑以及解决方案。 系列第一篇文章给了 OpenVLA&#xff0c;该模型是具身智能与VLA领域的必读模型之一&#xff0c;虽然现在有很多模型号称超越了它&#xff0c;但作为行业的基石仍然有非常高的地位。 项目链接&…...

Web3:Ubuntu系统 使用Docker-compose方式部署blockscout浏览器配置版本-v5.2.3-beta+charts图表

最近同事告诉我说要重新部署一套blockscout浏览器,我一想,之前有部署流程文档-《Web3:使用Docker-compose方式部署blockscout浏览器+charts图表》,这不手拿把掐吗。 但还是出现了一些问题,之前服务器系统是centos,现在是Ubuntu系统,而且之前docker镜像也没那么难获取,于…...

ECharts-柱状图

柱状图样式设置 Ⅰ、柱条样式 柱条的样式可以通过 series.itemStyle 设置&#xff0c;包括&#xff1a; 柱条的颜色&#xff08;color&#xff09;&#xff1b;柱条的描边颜色&#xff08;borderColor&#xff09;、宽度&#xff08;borderWidth&#xff09;、样式&#xff…...

理解UDP协议

在计算机网络中&#xff0c;UDP&#xff08;用户数据报协议&#xff09;常被称为“轻量级”传输协议。它不像TCP那样追求可靠传输&#xff0c;而是以简洁高效的设计满足特定场景的需求。本文将带你深入UDP的核心特性、技术细节及其实际应用。 UDP的协议设计​​ UDP协议的核心…...

Web 技术与 Nginx 网站环境部署

这里写目录标题 一. Web基础域名和DNS域名的概念域名的结构域名结构类型 Hosts文件Hosts文件的作用修改Hosts文件 DNS域名注册 网页与HTML网页概述HTML概述HTML基本标签HTML语法规则HTML文件结构 网站和主页Web1.0 与 Web2.0 静态网页与动态网页静态网页动态网页动态网页语言 H…...

分布式天线系统 (DAS, Distributed Antenna System)

1. 概述 分布式天线系统&#xff08;DAS&#xff09; 是一种通过多个分散的天线节点来增强无线信号覆盖和容量的网络架构。它主要用于解决大型建筑、地下设施、体育场馆等场景中的信号盲区或容量不足问题。 2. 主要组成 DAS系统通常包括以下关键组件&#xff1a; 信号源&…...

hexo博客搭建使用

搭建 Hexo 演示主题为&#xff1a;Keep 使用 文章 创建新文章 ➜ zymore-blog-keep git:(main) ✗ hexo new "告别H5嵌入&#xff01;uniApp小程序文件下载与分享完整解决方案" INFO Validating config INFO Created: ~/Desktop/HelloWorld/zymore-blog-k…...

Git上传项目到GitHub

Git上传项目到GitHub 下载Git客户端配置Git设置GitHub上传本地项目到Github 下载Git客户端 网址&#xff1a;Git Windows客户端。选择Standalone Installer(单独安装程序)&#xff0c;并点击64bit Git for Windows Setup(64位Git for Windows安装程序)进行下载。然后一路默认选…...

隨筆20250519 Async+ThreadPoolTaskExecutor⾃定义线程池进阶实战

1.ThreadPoolTaskExecutor线程池 有哪⼏个重要参数&#xff0c; 什么时候会创建线程 1.核心綫程數 查看核心綫程數目是否已經滿&#xff0c;未滿 創建一條綫程 執行任務&#xff0c;已滿負責執行第二部 2.阻塞隊列 查看阻塞隊列是否已經滿&#xff0c;未滿將任務加入阻塞隊列&…...

YoloV8改进策略:卷积篇|风车卷积|即插即用

文章目录 论文信息论文翻译摘要引言相关研究红外搜索与跟踪检测和分割网络红外搜索与跟踪数据集的损失函数红外搜索与跟踪数据集方法风车形卷积(PConv)基于尺度的动态损失SIRST - UAVB数据集实验实验设置与其他方法的比较多模型上的消融实验结论致谢代码改进方法测试结果总结…...

HGDB中如何为表增加自增主键

文章目录 环境文档用途详细信息 环境 系统平台&#xff1a;N/A 版本&#xff1a;4.5 文档用途 本文主要介绍在瀚高数据库中如何为表增加新主键&#xff0c;便于业务改造和查询。 实现原理&#xff1a;通过添加序列自增字段和唯一约束实现。 详细信息 可以根据数字类型来设…...

升级mysql (rpm安装)

#备份以防万一 备份配置文件: /etc/my.cnf.d/server.cnf 备份数据: mysqldump -u your_username -p --all-databases > all_databases.sql #停止 systemctl stop mysql #卸载旧版 yum remove mariadb #安装新版( 通过yum安装报错,死活安装不了,只能rpm安装) 下载地址…...

ALTER COLLATION使用场景

ALTER COLLATION 是 SQL 中用于修改字符集排序规则&#xff08;Collation&#xff09;的操作。排序规则定义了字符数据的比较和排序方式&#xff0c;包括字母顺序、大小写敏感性、重音符号处理等。ALTER COLLATION 的使用场景主要集中在需要调整数据库或表的字符集排序规则时。…...

Python实例题:Python 实现简易 Shell

目录 Python实例题 题目 代码实现 功能说明 基本命令执行&#xff1a; 内置命令&#xff1a; 环境变量&#xff1a; 管道&#xff1a; 重定向&#xff1a; 信号处理&#xff1a; 使用方法 注意事项 Python实例题 题目 Python 实现简易 Shell 代码实现 import o…...

大中型病险水库大坝除险加固监测实施方案

一、方案背景 我国80%以上的水库修建于20世纪50至70年代&#xff0c;经过几十年的运行&#xff0c;大部分水库已超过设计使用年限&#xff0c;功能老化现象较严重&#xff0c;出现病险具有一定的客观性。受超标洪水、强烈地震等自然灾害影响&#xff0c;水库一旦遭遇突发暴雨洪…...

[长城杯 2024]anote

题解前的小吐槽:终于还是狠下心复现了一下长城杯的这个赛题&#xff0c;第一次觉得汇编比函数看的方便&#xff0c;不过这题好写是好写的[心虚](还是看了一些大佬的wp) [长城杯 2024]anote(堆溢出C) [长城杯 2024]anote 1.准备 motalymotaly-VMware-Virtual-Platform:~$ fi…...

verify_ssl 与 Token 验证的区别详解

verify_ssl 与 Token 验证的区别详解 在开发或调用 API 接口时&#xff0c;我们经常会遇到两个看似相关但实际上作用完全不同的安全参数&#xff1a; 传输层的 verify_ssl应用层的 Authorization&#xff08;最常见是 Bearer Token&#xff09; 虽然它们都与“安全”有关&am…...

Python集合

一、Python集合概述 Python集合(set)是一种无序、可变且不包含重复元素的数据结构。集合在Python中通过哈希表实现&#xff0c;这使得它在成员检测和去重操作中具有极高的效率。 集合与列表、元组的主要区别&#xff1a; 无序性&#xff1a;元素没有固定顺序 唯一性&#x…...

容器化-K8s-镜像仓库使用和应用

一、K8s 镜像仓库使用 1、启动镜像仓库 cd/usr/local/harbor ./install.sh2、配置镜像仓库地址 在 master 节点和 slaver 节点上,需要配置 Docker 的镜像仓库地址,以便能够访问本地的镜像仓库。编辑 Docker 的配置文件 vi /etc/docker/daemon.json(如果不存在则创建),添…...

解决报错 Flask-SQLAlchemy TypeError: ‘float‘ object is not callable

Flask-SQLAlchemy TypeError: ‘float’ object is not callable Flask-SQLAlchemy 与 Python 版本兼容性问题解决方案 日期&#xff1a;2025 年 5 月 19 日 分类&#xff1a;后端开发、Python、Flask 标签&#xff1a;Flask-SQLAlchemy, Python 版本兼容&#xff0c;错误修复…...