结构型设计模式-适配器等 (汇总)

88 阅读18分钟

重点学习 适配器、装饰器设计模式

适配器模式

现有功能拓展,或者现有方法内部实现的前、后新增代码

伪代码

适配器模式(Adapter Pattern)用于将一个类的接口转换成客户期望的另一个接口。以下是适配器模式的伪代码示例:

pseudo
Copy code
// 客户端期望的目标接口
interface Target {
    request(): void
}

// 需要被适配的类
class Adaptee {
    specificRequest(): void {
        // 具体的实现逻辑
    }
}

// 适配器类,将Adaptee适配到Target接口
class Adapter implements Target {
    private adaptee: Adaptee

    constructor(adaptee: Adaptee) {
        this.adaptee = adaptee
    }

    request(): void {
        // 调用Adaptee的特殊请求方法来实现目标接口
        this.adaptee.specificRequest()
    }
}

// 客户端代码
function clientCode(target: Target): void {
    target.request()
}

// 在客户端中使用适配器
let adaptee = new Adaptee()
let adapter = new Adapter(adaptee)
clientCode(adapter)

在上面的示例中,Adaptee 类拥有一个 specificRequest 方法,而 Target 接口定义了一个 request 方法。通过创建一个适配器类 Adapter,它实现了 Target 接口,并在 request 方法中调用了 AdapteespecificRequest 方法,从而使得 Adaptee 的功能可以被客户端通过 Target 接口来访问。

高级用法-对象适配器 (常用就是这种)

高级用法-类适配器 (继承)

// 目标接口
interface Target {
    request();
}

// 适配者类,需要被适配的类
class Adaptee {
    specificRequest();
}

// 适配器类,继承自适配者类,并实现目标接口
class Adapter extends Adaptee implements Target {
    // 实现目标接口的方法,通过调用适配者类的方法来实现适配
    request() {
        specificRequest();
    }
}

// 客户端代码
class Client {
    main() {
        // 创建适配器对象
        Target adapter = new Adapter();
        // 调用目标接口的方法,实际上是调用适配器类中的方法
        adapter.request();
    }
}

在上面的示例中,适配器类 Adapter 继承自适配者类 Adaptee,并实现了目标接口 Target。这样,适配器就可以将适配者的方法转换为目标接口的方法。客户端代码只需要与目标接口交互,无需直接与适配者类交互,从而实现了适配器模式的作用。

高级用法-多重适配

多重适配器是指一个适配器同时适配多个类或接口的情况。以下是伪代码示例:

plaintext
Copy code
// 目标接口
interface Target {
    request();
}

// 适配者类1
class Adaptee1 {
    specificRequest1();
}

// 适配者类2
class Adaptee2 {
    specificRequest2();
}

// 适配器类,实现目标接口,并持有适配者类的实例
class Adapter implements Target {
    Adaptee1 adaptee1;
    Adaptee2 adaptee2;

    // 构造函数,初始化适配者类的实例
    Adapter(Adaptee1 adaptee1, Adaptee2 adaptee2) {
        this.adaptee1 = adaptee1;
        this.adaptee2 = adaptee2;
    }

    // 实现目标接口的方法,通过适配者类的方法来实现适配
    request() {
        adaptee1.specificRequest1();
        adaptee2.specificRequest2();
    }
}

// 客户端代码
class Client {
    main() {
        // 创建适配者类的实例
        Adaptee1 adaptee1 = new Adaptee1();
        Adaptee2 adaptee2 = new Adaptee2();
        // 创建适配器对象,并传入适配者类的实例
        Target adapter = new Adapter(adaptee1, adaptee2);
        // 调用目标接口的方法,实际上是调用适配器类中的方法
        adapter.request();
    }
}

在上面的示例中,适配器类 Adapter 同时持有两个适配者类 Adaptee1Adaptee2 的实例,并实现了目标接口 Target。适配器类的 request 方法中调用了两个适配者类的方法,从而实现了多重适配。

高级用法-接口转换

参考对象适配器的实现 区别在于: 对象适配器的被适配的对象可以通过组合的方式处理; 但接口转换的适配,一般被适配的对象采用从外部传入,采用聚合的方式;

高级用法-动态适配

动态适配器是指在运行时根据需要动态选择适配的对象。以下是伪代码示例:

plaintext
Copy code
// 目标接口
interface Target {
    request();
}

// 适配者类1
class Adaptee1 {
    specificRequest1();
}

// 适配者类2
class Adaptee2 {
    specificRequest2();
}

// 适配器类,实现目标接口,并持有适配者类的实例
class Adapter implements Target {
    Object adaptee;

    // 构造函数,初始化适配者类的实例
    Adapter(Object adaptee) {
        this.adaptee = adaptee;
    }

    // 实现目标接口的方法,通过适配者类的方法来实现适配
    request() {
        if (adaptee instanceof Adaptee1) {
            ((Adaptee1)adaptee).specificRequest1();
        } else if (adaptee instanceof Adaptee2) {
            ((Adaptee2)adaptee).specificRequest2();
        }
    }
}

// 客户端代码
class Client {
    main() {
        // 根据需要动态选择适配的对象
        Adaptee1 adaptee1 = new Adaptee1();
        Target adapter1 = new Adapter(adaptee1);
        adapter1.request();

        Adaptee2 adaptee2 = new Adaptee2();
        Target adapter2 = new Adapter(adaptee2);
        adapter2.request();
    }
}

在上面的示例中,适配器类 Adapter 中的 adaptee 属性是一个泛型对象,可以动态地传入不同类型的适配者对象。在 request 方法中,根据适配者对象的实际类型进行不同的处理,从而实现动态适配。

高级用法-适配器和装饰器结合 (注意)

当适配器和装饰器组合使用时,适配器可以用来适配现有的接口,使其与装饰器兼容。这种组合的高级用法可以在需要对现有对象进行功能增强,同时又需要与其他接口进行兼容时使用。以下是伪代码示例:

plaintext
Copy code
// 目标接口
interface Target {
    request();
}

// 适配者接口
interface Adaptee {
    specificRequest();
}

// 适配器类,实现目标接口,并持有适配者接口的实例
class Adapter implements Target {
    Adaptee adaptee;

    // 构造函数,初始化适配者接口的实例
    Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    // 实现目标接口的方法,通过适配者接口的方法来实现适配
    request() {
        adaptee.specificRequest();
    }
}

// 装饰器类,实现目标接口,并持有目标接口的实例
class Decorator implements Target {
    Target target;

    // 构造函数,初始化目标接口的实例
    Decorator(Target target) {
        this.target = target;
    }

    // 实现目标接口的方法,并在其中增加装饰功能
    request() {
        // 调用目标接口的方法
        target.request();
        // 在方法调用前后增加装饰功能
        // ...
    }
}

// 使用适配器和装饰器组合的高级用法
// 创建适配者对象
Adaptee adaptee = new AdapteeImpl();
// 创建适配器对象,并将适配者对象传入
Adapter adapter = new Adapter(adaptee);
// 创建装饰器对象,并将适配器对象传入
Decorator decorator = new Decorator(adapter);
// 使用装饰器对象调用方法,实现对目标对象的功能增强
decorator.request();

在上面的示例中,适配器 Adapter 将适配者接口 Adaptee 适配到了目标接口 Target 上,使其能够被装饰器 Decorator 使用。然后,装饰器 Decorator 在调用目标接口的方法时,可以在方法调用前后增加额外的功能,实现对目标对象的功能增强。

高级用法-适配器和代理组合

高级用法-适配器和责任链组合

高级用法-适配器和观察者组合

高级用法-适配器和命令组合

装饰器模式

伪代码

装饰器模式允许在不改变对象接口的情况下动态地将责任附加到对象上。下面是装饰器模式的简单伪代码示例:

plaintext
Copy code
// 定义组件接口
interface Component {
    operation()
}

// 具体组件实现
class ConcreteComponent implements Component {
    operation() {
        // 实现具体操作
    }
}

// 装饰器抽象类
class Decorator implements Component {
    protected component: Component
    
    constructor(component: Component) {
        this.component = component
    }
    
    operation() {
        this.component.operation()
    }
}

// 具体装饰器类
class ConcreteDecoratorA extends Decorator {
    addedState: string
    
    constructor(component: Component) {
        super(component)
        this.addedState = "New State"
    }
    
    operation() {
        super.operation()
        // 在原有操作基础上添加新的操作
    }
}

// 客户端代码
component = new ConcreteComponent()
decoratedComponent = new ConcreteDecoratorA(component)
decoratedComponent.operation()

在上面的示例中,Component 是一个接口,定义了操作的抽象方法。ConcreteComponent 是具体的组件实现。Decorator 是装饰器的抽象类,实现了与组件相同的接口,并持有一个组件对象。ConcreteDecoratorA 是具体的装饰器类,继承自 Decorator,在原有操作的基础上添加了新的操作。客户端代码通过创建具体组件对象,并将其传递给装饰器对象,实现了动态地添加新功能而不改变原有接口的效果。

高级用法-简单装饰器

简单装饰器模式通常用于在不改变接口的情况下给对象添加新的行为或功能。以下是一个伪代码示例:

plaintext
Copy code
// 定义接口
interface Component {
    operation(): void
}

// 具体组件类
class ConcreteComponent implements Component {
    operation() {
        // 原始操作
    }
}

// 装饰器类
class Decorator implements Component {
    protected component: Component

    constructor(component: Component) {
        this.component = component
    }

    operation() {
        // 委托给被装饰对象执行操作
        this.component.operation()
    }
}

// 具体装饰器类,添加额外功能
class ConcreteDecoratorA extends Decorator {
    operation() {
        // 执行额外操作
        super.operation()
        // 添加的功能
    }
}

// 客户端代码
function clientCode(component: Component) {
    component.operation()
}

// 使用装饰器
let simpleComponent = new ConcreteComponent()
let decoratedComponent = new ConcreteDecoratorA(simpleComponent)
clientCode(decoratedComponent)

在这个示例中,ConcreteComponent是具体的组件类,Decorator是装饰器抽象类,ConcreteDecoratorA是具体的装饰器类。通过创建具体装饰器类并将原始组件传递给它,可以在不改变原始组件接口的情况下为原始组件添加额外的功能。

高级用法-动态装饰器链

动态装饰器链是指在运行时动态地组合多个装饰器,形成一个装饰器链,以便在调用操作时依次执行这些装饰器的功能。以下是使用动态装饰器链的伪代码示例:

// 定义组件接口
interface Component {
    operation(): void
}

// 具体组件实现
class ConcreteComponent implements Component {
    operation() {
        // 执行具体组件的操作
    }
}

// 定义装饰器基类
abstract class Decorator implements Component {
    protected component: Component
    
    constructor(component: Component) {
        this.component = component
    }
    
    operation() {
        // 将操作委托给被装饰对象
        this.component.operation()
    }
}

// 动态装饰器链类
class DecoratorChain implements Component {
    private decorators: Decorator[] = []
    
    addDecorator(decorator: Decorator) {
        this.decorators.push(decorator)
    }
    
    operation() {
        // 依次调用装饰器链中的装饰器的操作
        for (let decorator of this.decorators) {
            decorator.operation()
        }
    }
}

// 客户端代码
// 创建具体组件对象
let component = new ConcreteComponent()
// 创建装饰器链对象
let chain = new DecoratorChain()
// 添加具体装饰器对象到装饰器链中
chain.addDecorator(new ConcreteDecorator1(component))
chain.addDecorator(new ConcreteDecorator2(component))
// 使用装饰器链对象执行操作
chain.operation()

在这个示例中,DecoratorChain 类负责管理装饰器链,并提供了 addDecorator 方法用于动态添加装饰器。客户端代码创建了具体组件对象和装饰器链对象,并将具体组件对象传递给装饰器链中的每个装饰器。当调用装饰器链对象的 operation 方法时,它会依次调用装饰器链中每个装饰器的 operation 方法,从而实现动态装饰器链的功能。

高级用法-条件装饰器

条件装饰器是一种特殊的装饰器,它根据特定条件来决定是否执行被装饰对象的操作。以下是使用条件装饰器的伪代码示例:

plaintext
Copy code
// 定义组件接口
interface Component {
    operation(): void
}

// 具体组件实现
class ConcreteComponent implements Component {
    operation() {
        // 执行具体组件的操作
    }
}

// 条件装饰器类
class ConditionalDecorator implements Component {
    private component: Component
    private condition: boolean
    
    constructor(component: Component, condition: boolean) {
        this.component = component
        this.condition = condition
    }
    
    operation() {
        // 根据条件决定是否执行操作
        if (this.condition) {
            this.component.operation()
        }
    }
}

// 客户端代码
// 创建具体组件对象
let component = new ConcreteComponent()
// 创建条件装饰器对象,传入具体组件对象和条件
let conditionalDecorator = new ConditionalDecorator(component, true)
// 调用装饰器的操作方法
conditionalDecorator.operation()

在这个示例中,ConditionalDecorator 类是一个条件装饰器,它接收一个具体组件对象和一个条件作为参数。在 operation 方法中,根据条件决定是否执行被装饰对象的操作。客户端代码创建了具体组件对象和条件装饰器对象,并调用了装饰器的 operation 方法。如果条件为真,则执行被装饰对象的操作,否则不执行。

高级用法-装饰器组合 (重要)

装饰器组合是指将多个装饰器按照一定的顺序组合起来,形成一个装饰器链,每个装饰器依次对原始组件进行装饰。以下是伪代码示例:

plaintext
Copy code
// 定义组件接口
interface Component {
    operation(): void
}

// 具体组件实现
class ConcreteComponent implements Component {
    operation() {
        // 执行具体组件的操作
    }
}

// 抽象装饰器类
class Decorator implements Component {
    protected component: Component
    
    constructor(component: Component) {
        this.component = component
    }
    
    operation() {
        this.component.operation()
    }
}

// 具体装饰器类1
class ConcreteDecorator1 extends Decorator {
    operation() {
        super.operation()
        // 执行额外的操作1
    }
}

// 具体装饰器类2
class ConcreteDecorator2 extends Decorator {
    operation() {
        super.operation()
        // 执行额外的操作2
    }
}

// 客户端代码
// 创建具体组件对象
let component = new ConcreteComponent()
// 创建具体装饰器对象,按照一定顺序进行组合
let decoratedComponent = new ConcreteDecorator2(new ConcreteDecorator1(component))
// 调用装饰器链的操作方法
decoratedComponent.operation()

在这个示例中,ConcreteDecorator1ConcreteDecorator2 是具体装饰器类,它们继承自抽象装饰器类 Decorator,并在 operation 方法中执行额外的操作。客户端代码创建了具体组件对象和装饰器链,按照一定的顺序组合了多个装饰器,然后调用装饰器链的 operation 方法,依次对原始组件进行装饰。

装饰器模式实现AOP(面向切面编程)

在面向切面编程(AOP)中,装饰器模式可以用来实现横切关注点的功能。下面是一个伪代码示例,演示了如何使用装饰器模式实现AOP功能:

plaintext
Copy code
// 定义切面接口
interface Aspect {
    // 在执行前切入的方法
    before(): void
    
    // 在执行后切入的方法
    after(): void
}

// 具体切面实现类
class LoggingAspect implements Aspect {
    before(): void {
        // 在执行前记录日志
        log("Before method execution")
    }
    
    after(): void {
        // 在执行后记录日志
        log("After method execution")
    }
}

// 定义服务接口
interface Service {
    execute(): void
}

// 具体服务类
class ConcreteService implements Service {
    execute(): void {
        // 执行具体的服务方法
        log("Executing service method")
    }
}

// 装饰器类
class AspectDecorator implements Service {
    protected service: Service
    protected aspect: Aspect
    
    constructor(service: Service, aspect: Aspect) {
        this.service = service
        this.aspect = aspect
    }
    
    execute(): void {
        // 在执行前应用切面
        this.aspect.before()
        // 执行被装饰对象的方法
        this.service.execute()
        // 在执行后应用切面
        this.aspect.after()
    }
}

// 客户端代码
// 创建具体服务对象
let concreteService: Service = new ConcreteService()
// 创建切面对象
let loggingAspect: Aspect = new LoggingAspect()
// 创建装饰器对象,并传入具体服务对象和切面对象
let decoratedService: Service = new AspectDecorator(concreteService, loggingAspect)
// 调用装饰后的服务方法,同时会在执行前后记录日志
decoratedService.execute()

在上面的示例中,AspectDecorator 类用来装饰具体的服务对象,并在执行服务方法前后应用切面。通过这种方式,我们可以实现AOP中的横切关注点,比如日志记录、性能监控等功能,而不需要在具体服务类中硬编码这些逻辑。

基于装饰器的插件系统

装饰器模式可以很好地用于设计插件系统,让系统具有可扩展性和灵活性。以下是一个伪代码示例,演示了如何使用装饰器模式设计插件系统:

plaintext
Copy code
// 插件接口
interface Plugin {
    // 执行插件逻辑的方法
    execute(): void
}

// 具体插件类
class ConcretePlugin implements Plugin {
    execute(): void {
        // 具体插件逻辑
    }
}

// 装饰器基类
abstract class PluginDecorator implements Plugin {
    protected plugin: Plugin
    
    constructor(plugin: Plugin) {
        this.plugin = plugin
    }
    
    // 执行插件逻辑的方法
    execute(): void {
        this.plugin.execute()
    }
}

// 具体装饰器类1
class PluginDecorator1 extends PluginDecorator {
    constructor(plugin: Plugin) {
        super(plugin)
    }
    
    // 执行插件逻辑的方法,可以在执行前后添加额外逻辑
    execute(): void {
        // 添加额外逻辑1
        super.execute()
        // 添加额外逻辑2
    }
}

// 具体装饰器类2
class PluginDecorator2 extends PluginDecorator {
    constructor(plugin: Plugin) {
        super(plugin)
    }
    
    // 执行插件逻辑的方法,可以在执行前后添加额外逻辑
    execute(): void {
        // 添加额外逻辑3
        super.execute()
        // 添加额外逻辑4
    }
}

// 客户端代码
// 创建具体插件对象
let concretePlugin: Plugin = new ConcretePlugin()
// 创建装饰器对象,并传入具体插件对象
let decoratedPlugin1: Plugin = new PluginDecorator1(concretePlugin)
let decoratedPlugin2: Plugin = new PluginDecorator2(decoratedPlugin1)

// 调用装饰后的插件方法,同时会在执行前后添加额外逻辑
decoratedPlugin2.execute()

在这个示例中,PluginDecorator 类是装饰器基类,用于装饰具体插件对象。通过创建不同的具体装饰器类,我们可以添加不同的额外逻辑,从而实现插件系统中的扩展功能。客户端代码可以根据需要选择并组合不同的装饰器,以满足具体业务需求。

代理模式

伪代码

代理设计模式允许你提供一个代理类,该代理类可以控制或代表其他对象的访问。这种模式通常用于实现延迟加载、访问控制、日志记录等功能。以下是一个简单的伪代码示例,演示了代理设计模式的基本实现:

python
Copy code
# 目标接口
interface Subject {
    request()
}

# 目标类
class RealSubject implements Subject {
    request() {
        print("RealSubject: Handling request.")
    }
}

# 代理类
class Proxy implements Subject {
    realSubject: RealSubject

    request() {
        // 在需要时创建真实主题对象
        if (realSubject == null) {
            realSubject = new RealSubject()
        }
        // 执行真实主题对象的请求
        realSubject.request()
    }
}

# 客户端代码
client() {
    // 创建代理对象
    proxy = new Proxy()
    // 通过代理对象发起请求
    proxy.request()
}

在上面的示例中,Subject 是目标接口,定义了真实主题类和代理类都需要实现的方法。RealSubject 是真实的主题类,它执行实际的业务逻辑。Proxy 是代理类,它持有一个对真实主题对象的引用,并在必要时创建和使用真实主题对象。客户端代码通过代理对象发起请求,而代理对象则负责将请求传递给真实的主题对象。

外观模式

伪代码

外观设计模式提供了一个统一的接口,用于访问子系统中的一组接口。它隐藏了子系统的复杂性,并提供了一个简单的接口给客户端。以下是外观设计模式的简单伪代码示例:

python
Copy code
# 定义一个子系统中的多个类和接口
class SubsystemA:
    def operation_a(self):
        print("SubsystemA: Operation A")

class SubsystemB:
    def operation_b(self):
        print("SubsystemB: Operation B")

class SubsystemC:
    def operation_c(self):
        print("SubsystemC: Operation C")

# 定义一个外观类,封装子系统中的操作,并提供一个简单的接口给客户端
class Facade:
    def __init__(self):
        self.subsystem_a = SubsystemA()
        self.subsystem_b = SubsystemB()
        self.subsystem_c = SubsystemC()

    def operation(self):
        print("Facade: Performing operations using subsystems...")
        self.subsystem_a.operation_a()
        self.subsystem_b.operation_b()
        self.subsystem_c.operation_c()

# 客户端代码通过外观类来访问子系统中的操作,而不需要直接与子系统中的类交互
facade = Facade()
facade.operation()

在上面的示例中,Facade 类封装了子系统中的多个类和接口,并提供了一个简单的 operation 方法给客户端调用。客户端只需要和外观类交互,而不需要直接与子系统中的类交互,从而简化了客户端的使用方式。

组合模式

伪代码

组合模式是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”的层次结构。下面是一个伪代码示例,演示了如何使用组合模式构建一个文件系统:

plaintext
Copy code
// 定义抽象组件(Component),表示文件系统中的文件或文件夹
interface Component {
    operation(): void
}

// 定义叶子节点(Leaf),表示文件
class File implements Component {
    name: string

    constructor(name: string) {
        this.name = name
    }

    operation(): void {
        print("File: " + this.name)
    }
}

// 定义复合节点(Composite),表示文件夹
class Folder implements Component {
    name: string
    children: Component[]

    constructor(name: string) {
        this.name = name
        this.children = []
    }

    add(component: Component): void {
        this.children.push(component)
    }

    remove(component: Component): void {
        const index = this.children.indexOf(component)
        if (index !== -1) {
            this.children.splice(index, 1)
        }
    }

    operation(): void {
        print("Folder: " + this.name)
        for (const child of this.children) {
            child.operation()
        }
    }
}

// 使用组合模式构建文件系统
const rootFolder = new Folder("Root")
const folder1 = new Folder("Folder 1")
const folder2 = new Folder("Folder 2")
const file1 = new File("File 1")
const file2 = new File("File 2")

folder1.add(file1)
folder2.add(file2)
rootFolder.add(folder1)
rootFolder.add(folder2)

// 调用操作方法,打印文件系统结构
rootFolder.operation()

在上面的示例中,Component 接口定义了操作方法 operation()File 类和 Folder 类分别表示叶子节点和复合节点。Folder 类中包含一个子组件列表 children,可以添加、移除子组件。通过将文件和文件夹组合成树形结构,可以轻松地遍历整个文件系统并执行操作。

桥接模式

伪代码

桥接模式是一种结构型设计模式,它将抽象部分与其实现部分分离,使它们可以独立地变化。以下是桥接模式的伪代码示例:

plaintext
Copy code
// 定义实现接口
interface Implementor {
    operationImpl();
}

// 具体实现类A
class ConcreteImplementorA implements Implementor {
    operationImpl() {
        // 实现A的操作逻辑
    }
}

// 具体实现类B
class ConcreteImplementorB implements Implementor {
    operationImpl() {
        // 实现B的操作逻辑
    }
}

// 定义抽象类
abstract class Abstraction {
    protected Implementor implementor;
    
    constructor(Implementor implementor) {
        this.implementor = implementor;
    }
    
    abstract operation();
}

// 扩展抽象类的具体实现类
class RefinedAbstraction extends Abstraction {
    constructor(Implementor implementor) {
        super(implementor);
    }
    
    operation() {
        // 调用实现部分的方法
        implementor.operationImpl();
    }
}

在这个示例中:

  • Implementor 是实现部分的接口,定义了实现类需要实现的操作。
  • ConcreteImplementorAConcreteImplementorB 是具体的实现类,实现了 Implementor 接口的方法。
  • Abstraction 是抽象部分的类,它持有一个 Implementor 实例,并声明了一个抽象的操作方法。
  • RefinedAbstractionAbstraction 的扩展类,实现了抽象类中的操作方法,并在其中调用了实现部分的方法。

桥接模式的关键是将抽象部分与其实现部分分离,使它们可以独立变化。这样,可以在不影响客户端的情况下更改实现部分的实现,或者在运行时动态地将实现部分替换为另一个。

桥接模式和适配器的接口适配区别

两者很像,只是出发点不一致;桥接模式一般用于接口和实现解耦;