整理好了!2024年最常见 20 道设计模式面试题(四)

上一篇地址:整理好了!2024年最常见 20 道设计模式面试题(三)-CSDN博客

七、请解释装饰者模式,并给出一个实际的应用场景。

装饰者模式(Decorator Pattern)也是一种结构型设计模式,它允许用户在不修改对象自身的基础上,通过添加额外的职责(即装饰)来扩展对象的功能。这种模式创建了一个装饰类,用来包装实际对象,从而在不改变实际对象的情况下,动态地给对象添加额外的行为。

装饰者模式的主要角色:

  1. 抽象组件(Component):定义了一个接口,描述可以动态添加的职责。
  2. 具体组件(ConcreteComponent):定义了抽象组件的具体实现,也就是被装饰的具体对象。
  3. 抽象装饰者(Decorator):持有一个Component接口,并定义了装饰接口。
  4. 具体装饰者(ConcreteDecorator):实现抽象装饰者,添加额外的职责,并委托给组件对象。

工作原理:

  1. 抽象组件定义了可以扩展的接口。
  2. 具体组件实现了抽象组件的接口。
  3. 抽象装饰者持有一个Component接口的引用,并实现与抽象组件相同的接口。
  4. 具体装饰者实现抽象装饰者,添加额外的职责,同时委托给组件对象的方法。

实际应用场景:

  1. 咖啡店的点单系统:顾客可以点一杯基础咖啡,然后根据需要添加不同的调料或装饰,如牛奶、糖、肉桂粉等。每添加一种调料,就相当于给咖啡对象添加了一个装饰者。

  2. GUI组件的动态扩展:在图形用户界面(GUI)中,可以动态地给组件添加不同的功能,比如给按钮添加边框、阴影等视觉效果。

  3. 网络通信:在网络通信中,可以动态地给消息添加额外的处理,如加密、压缩等。

  4. 日志记录:在软件系统中,可以给方法动态添加日志记录功能,而不需要修改方法本身的代码。

示例代码(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)是一种结构型设计模式,它为其他对象提供一个代替或占位符,以控制对它的访问。代理模式可以在不修改原始对象(即被代理对象)的情况下,通过引入一个代理层来间接操作对象。代理模式主要有以下几种类型:

  1. 远程代理(Remote Proxy)

    • 远程代理为位于不同地址空间的对象提供代理,隐藏对象位于不同地址空间的事实。它通常用于分布式系统中,客户端通过远程代理与远程对象进行通信。
  2. 虚拟代理(Virtual Proxy)

    • 虚拟代理用于延迟初始化资源密集型的对象。当对象的创建成本很高时,可以先使用一个轻量级的代理对象,直到真正需要时才创建实际对象。
  3. 保护代理(Protection Proxy)

    • 保护代理控制对原始对象的访问,根据不同的访问权限提供不同的访问策略。它可以用来实现不同级别的安全控制。
  4. 智能引用(Smart Reference)

    • 智能引用代理在访问对象时执行额外的操作。例如,它可以在调用方法前后添加日志记录、验证参数有效性等。
  5. 缓存代理(Cache Proxy)

    • 缓存代理存储对原始对象的引用或结果,以避免重复的计算或数据库查询。它可以用于实现数据缓存,提高性能。
  6. 同步代理(Synchronization Proxy)

    • 同步代理为对象的使用提供线程安全的访问。它确保在多线程环境中,对共享资源的访问是同步的。
  7. 防火墙代理(Firewall Proxy)

    • 防火墙代理在客户端和目标对象之间提供安全控制,防止未授权的访问。
  8. 复制代理(Copy-on-Write Proxy)

    • 复制代理用于延迟复制对象,直到对象被修改时才进行复制。这可以用于优化性能,特别是在对象可能不会被修改的情况下。

每种代理模式的解释:

  • 远程代理:在分布式系统中,客户端可能需要与远程服务器上的对象进行交互。远程代理可以作为远程对象的本地代表,处理网络通信和对象请求转发。

  • 虚拟代理:当创建一个对象需要很长时间或消耗大量资源时,可以使用虚拟代理来代替。例如,加载一个大型图像或文档时,可以先显示一个缩略图或加载指示器。

  • 保护代理:保护代理确保只有具有适当权限的用户才能访问对象。例如,访问一个受保护的资源,代理会检查用户的权限。

  • 智能引用:智能引用代理在访问对象时添加额外的逻辑,如引用计数、访问日志记录等。

  • 缓存代理:缓存代理存储对象的状态或计算结果,以避免重复的计算。例如,Web应用程序中的页面缓存。

  • 同步代理:在多线程环境中,同步代理确保对共享资源的访问是线程安全的,防止数据竞争和一致性问题。

  • 防火墙代理:防火墙代理作为一种安全机制,控制对敏感对象的访问,防止未授权的访问和潜在的安全威胁。

  • 复制代理:复制代理用于优化性能,当对象可能不会被修改时,可以延迟复制操作,直到对象被实际修改。

每种代理模式都提供了一种机制,允许在不直接与原始对象交互的情况下,通过代理来控制、优化或保护对对象的访问。

  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值