//
//  Bridge.swift
//  Design
//
//  Created by 钟维 on 2022/3/22.
//

import Foundation
import XCTest

/*
 桥接模式是一种结构型设计模式， 可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构， 从而能在开发时分别使用。
 桥接模式结构
 
 1 抽象部分 （Abstraction） 提供高层控制逻辑， 依赖于完成底层实际工作的实现对象。
 2 实现部分 （Implementation） 为所有具体实现声明通用接口。 抽象部分仅能通过在这里声明的方法与实现对象交互。抽象部分可以列出和实现部分一样的方法， 但是抽象部分通常声明一些复杂行为， 这些行为依赖于多种由实现部分声明的原语操作。
 3 具体实现 （Concrete Implementations） 中包括特定于平台的代码。
 4 精确抽象 （Refined Abstraction） 提供控制逻辑的变体。 与其父类一样， 它们通过通用实现接口与不同的实现进行交互。
 5 通常情况下， 客户端 （Client） 仅关心如何与抽象部分合作。 但是， 客户端需要将抽象对象与一个实现对象连接起来。
 
 桥接可以通过一些控制实体及其所依赖的多个不同平台之间的明确区别来进行识别
*/

/// 抽象部分 （Abstraction） 提供高层控制逻辑， 依赖于完成底层实际工作的实现对象。
class Abstraction {
    
    fileprivate var implementation: Implementation
    init(_ implementation: Implementation) {
        self.implementation = implementation
    }
    func operation() -> String {
        let operation = implementation.operationImplementation()
        return "Abstraction: Base operation with:\n" + operation
    }
}

/// 具体实现 （Concrete Implementations） 中包括特定于平台的代码。
class ExtendedAbstraction: Abstraction {
    
    override func operation() -> String {
        let operation = implementation.operationImplementation()
        return "ExtendedAbstraction: Extended operation with:\n" + operation
    }
}

// 实现部分 （Implementation） 为所有具体实现声明通用接口。 抽象部分仅能通过在这里声明的方法与实现对象交互。抽象部分可以列出和实现部分一样的方法， 但是抽象部分通常声明一些复杂行为， 这些行为依赖于多种由实现部分声明的原语操作。
protocol Implementation {
    func operationImplementation() -> String
}

// 具体实现 （Concrete Implementations） 中包括特定于平台的代码。
class ConcreteImplementationA: Implementation {
    
    func operationImplementation() -> String {
        return "ConcreteImplementationA: Here's the result on the platform A.\n"
    }
}

// 具体实现 （Concrete Implementations） 中包括特定于平台的代码。
class ConcreteImplementationB: Implementation {
    
    func operationImplementation() -> String {
        return "ConcreteImplementationB: Here's the result on the platform B\n"
    }
}

// 通常情况下， 客户端 （Client） 仅关心如何与抽象部分合作。 但是， 客户端需要将抽象对象与一个实现对象连接起来。
class BridgeClient {
    
    static func someClientCode(abstraction: Abstraction) {
        print(abstraction.operation())
    }
}

class BridgeConceptual: XCTestCase {

    func testBridgeConceptual() {
        
        let implementation = ConcreteImplementationA()
        BridgeClient.someClientCode(abstraction: Abstraction(implementation))
        
        let concreteImplementation = ConcreteImplementationB()
        BridgeClient.someClientCode(abstraction: ExtendedAbstraction(concreteImplementation))
    }
}

