上一篇地址:整理好了!2024年最常见 20 道设计模式面试题(三)-CSDN博客
七、请解释装饰者模式,并给出一个实际的应用场景。
装饰者模式(Decorator Pattern)也是一种结构型设计模式,它允许用户在不修改对象自身的基础上,通过添加额外的职责(即装饰)来扩展对象的功能。这种模式创建了一个装饰类,用来包装实际对象,从而在不改变实际对象的情况下,动态地给对象添加额外的行为。
装饰者模式的主要角色:
- 抽象组件(Component):定义了一个接口,描述可以动态添加的职责。
- 具体组件(ConcreteComponent):定义了抽象组件的具体实现,也就是被装饰的具体对象。
- 抽象装饰者(Decorator):持有一个Component接口,并定义了装饰接口。
- 具体装饰者(ConcreteDecorator):实现抽象装饰者,添加额外的职责,并委托给组件对象。
工作原理:
- 抽象组件定义了可以扩展的接口。
- 具体组件实现了抽象组件的接口。
- 抽象装饰者持有一个Component接口的引用,并实现与抽象组件相同的接口。
- 具体装饰者实现抽象装饰者,添加额外的职责,同时委托给组件对象的方法。
实际应用场景:
-
咖啡店的点单系统:顾客可以点一杯基础咖啡,然后根据需要添加不同的调料或装饰,如牛奶、糖、肉桂粉等。每添加一种调料,就相当于给咖啡对象添加了一个装饰者。
-
GUI组件的动态扩展:在图形用户界面(GUI)中,可以动态地给组件添加不同的功能,比如给按钮添加边框、阴影等视觉效果。
-
网络通信:在网络通信中,可以动态地给消息添加额外的处理,如加密、压缩等。
-
日志记录:在软件系统中,可以给方法动态添加日志记录功能,而不需要修改方法本身的代码。
示例代码(Java):
// 抽象组件
interface Coffee {
String getDescription();
double cost();
}
// 具体组件
class SimpleCoffee implements Coffee {
@Override
public String getDescription() {
return "Simple Coffee";
}
@Override
public double cost() {
return 10.0;
}
}
// 抽象装饰者
abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public String getDescription() {
return coffee.getDescription();
}
@Override
public double cost() {
return coffee.cost();
}
}
// 具体装饰者
class MilkCoffee extends CoffeeDecorator {
public MilkCoffee(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + ", Milk";
}
@Override
public double cost() {
return coffee.cost() + 2.0;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
Coffee milkCoffee = new MilkCoffee(coffee);
System.out.println("Coffee: " + coffee.getDescription() + ", Cost: " + coffee.cost());
System.out.println("Milk Coffee: " + milkCoffee.getDescription() + ", Cost: " + milkCoffee.cost());
}
}
在这个示例中,Coffee
是抽象组件,SimpleCoffee
是具体组件。CoffeeDecorator
是抽象装饰者,MilkCoffee
是具体装饰者,它给咖啡添加了牛奶的职责。客户端代码演示了如何使用装饰者模式来动态地扩展咖啡的功能。
八、代理模式有哪些类型?请分别解释它们。
代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一个代替或占位符,以控制对它的访问。代理模式可以在不修改原始对象(即被代理对象)的情况下,通过引入一个代理层来间接操作对象。代理模式主要有以下几种类型:
-
远程代理(Remote Proxy):
- 远程代理为位于不同地址空间的对象提供代理,隐藏对象位于不同地址空间的事实。它通常用于分布式系统中,客户端通过远程代理与远程对象进行通信。
-
虚拟代理(Virtual Proxy):
- 虚拟代理用于延迟初始化资源密集型的对象。当对象的创建成本很高时,可以先使用一个轻量级的代理对象,直到真正需要时才创建实际对象。
-
保护代理(Protection Proxy):
- 保护代理控制对原始对象的访问,根据不同的访问权限提供不同的访问策略。它可以用来实现不同级别的安全控制。
-
智能引用(Smart Reference):
- 智能引用代理在访问对象时执行额外的操作。例如,它可以在调用方法前后添加日志记录、验证参数有效性等。
-
缓存代理(Cache Proxy):
- 缓存代理存储对原始对象的引用或结果,以避免重复的计算或数据库查询。它可以用于实现数据缓存,提高性能。
-
同步代理(Synchronization Proxy):
- 同步代理为对象的使用提供线程安全的访问。它确保在多线程环境中,对共享资源的访问是同步的。
-
防火墙代理(Firewall Proxy):
- 防火墙代理在客户端和目标对象之间提供安全控制,防止未授权的访问。
-
复制代理(Copy-on-Write Proxy):
- 复制代理用于延迟复制对象,直到对象被修改时才进行复制。这可以用于优化性能,特别是在对象可能不会被修改的情况下。
每种代理模式的解释:
-
远程代理:在分布式系统中,客户端可能需要与远程服务器上的对象进行交互。远程代理可以作为远程对象的本地代表,处理网络通信和对象请求转发。
-
虚拟代理:当创建一个对象需要很长时间或消耗大量资源时,可以使用虚拟代理来代替。例如,加载一个大型图像或文档时,可以先显示一个缩略图或加载指示器。
-
保护代理:保护代理确保只有具有适当权限的用户才能访问对象。例如,访问一个受保护的资源,代理会检查用户的权限。
-
智能引用:智能引用代理在访问对象时添加额外的逻辑,如引用计数、访问日志记录等。
-
缓存代理:缓存代理存储对象的状态或计算结果,以避免重复的计算。例如,Web应用程序中的页面缓存。
-
同步代理:在多线程环境中,同步代理确保对共享资源的访问是线程安全的,防止数据竞争和一致性问题。
-
防火墙代理:防火墙代理作为一种安全机制,控制对敏感对象的访问,防止未授权的访问和潜在的安全威胁。
-
复制代理:复制代理用于优化性能,当对象可能不会被修改时,可以延迟复制操作,直到对象被实际修改。
每种代理模式都提供了一种机制,允许在不直接与原始对象交互的情况下,通过代理来控制、优化或保护对对象的访问。