
Swift 桥接模式讲解和代码示例
桥接是一种结构型设计模式, 可将业务逻辑或一个大类拆分为不同的层次结构, 从而能独立地进行开发。
层次结构中的第一层 (通常称为抽象部分) 将包含对第二层 (实现部分) 对象的引用。 抽象部分将能将一些 (有时是绝大部分) 对自己的调用委派给实现部分的对象。 所有的实现部分都有一个通用接口, 因此它们能在抽象部分内部相互替换。
复杂度:
流行度:
使用示例: 桥接模式在处理跨平台应用、 支持多种类型的数据库服务器或与多个特定种类 (例如云平台和社交网络等) 的 API 供应商协作时会特别有用。
识别方法: 桥接可以通过一些控制实体及其所依赖的多个不同平台之间的明确区别来进行识别。
以下示例可在
Swift Playgrounds
上使用。
感谢
Alejandro Mohamad 创建了Playground版本。
概念示例
本例说明了桥接设计模式的结构并重点回答了下面的问题:
- 它由哪些类组成?
- 这些类扮演了哪些角色?
- 模式中的各个元素会以何种方式相互关联?
了解该模式的结构后, 你可以更容易地理解下面基于真实世界的 Swift 应用案例。
Example.swift: 概念示例
import XCTest
/// The Abstraction defines the interface for the "control" part of the two
/// class hierarchies. It maintains a reference to an object of the
/// Implementation hierarchy and delegates all of the real work to this object.
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
}
}
/// You can extend the Abstraction without changing the Implementation classes.
class ExtendedAbstraction: Abstraction {
override func operation() -> String {
let operation = implementation.operationImplementation()
return "ExtendedAbstraction: Extended operation with:\n" + operation
}
}
/// The Implementation defines the interface for all implementation classes. It
/// doesn't have to match the Abstraction's interface. In fact, the two
/// interfaces can be entirely different. Typically the Implementation interface
/// provides only primitive operations, while the Abstraction defines higher-
/// level operations based on those primitives.
protocol Implementation {
func operationImplementation() -> String
}
/// Each Concrete Implementation corresponds to a specific platform and
/// implements the Implementation interface using that platform's API.
class ConcreteImplementationA: Implementation {
func operationImplementation() -> String {
return "ConcreteImplementationA: Here's the result on the platform A.\n"
}
}
class ConcreteImplementationB: Implementation {
func operationImplementation() -> String {
return "ConcreteImplementationB: Here's the result on the platform B\n"
}
}
/// Except for the initialization phase, where an Abstraction object gets linked
/// with a specific Implementation object, the client code should only depend on
/// the Abstraction class. This way the client code can support any abstraction-
/// implementation combination.
class Client {
// ...
static func someClientCode(abstraction: Abstraction) {
print(abstraction.operation())
}
// ...
}
/// Let's see how it all works together.
class BridgeConceptual: XCTestCase {
func testBridgeConceptual() {
// The client code should be able to work with any pre-configured
// abstraction-implementation combination.
let implementation = ConcreteImplementationA()
Client.someClientCode(abstraction: Abstraction(implementation))
let concreteImplementation = ConcreteImplementationB()
Client.someClientCode(abstraction: ExtendedAbstraction(concreteImplementation))
}
}
Output.txt: 执行结果
Abstraction: Base operation with:
ConcreteImplementationA: Here's the result on the platform A
ExtendedAbstraction: Extended operation with:
ConcreteImplementationB: Here's the result on the platform B
真实世界示例
Example.swift: 真实世界示例
import XCTest
private class BridgeRealWorld: XCTestCase {
func testBridgeRealWorld() {
print("Client: Pushing Photo View Controller...")
push(PhotoViewController())
print()
print("Client: Pushing Feed View Controller...")
push(FeedViewController())
}
func push(_ container: SharingSupportable) {
let instagram = InstagramSharingService()
let facebook = FaceBookSharingService()
container.accept(service: instagram)
container.update(content: foodModel)
container.accept(service: facebook)
container.update(content: foodModel)
}
var foodModel: Content {
return FoodDomainModel(title: "This food is so various and delicious!",
images: [UIImage(), UIImage()],
calories: 47)
}
}
private protocol SharingSupportable {
/// Abstraction
func accept(service: SharingService)
func update(content: Content)
}
class BaseViewController: UIViewController, SharingSupportable {
fileprivate var shareService: SharingService?
func update(content: Content) {
/// ...updating UI and showing a content...
/// ...
/// ... then, a user will choose a content and trigger an event
print("\(description): User selected a \(content) to share")
/// ...
shareService?.share(content: content)
}
func accept(service: SharingService) {
shareService = service
}
}
class PhotoViewController: BaseViewController {
/// Custom UI and features
override var description: String {
return "PhotoViewController"
}
}
class FeedViewController: BaseViewController {
/// Custom UI and features
override var description: String {
return "FeedViewController"
}
}
protocol SharingService {
/// Implementation
func share(content: Content)
}
class FaceBookSharingService: SharingService {
func share(content: Content) {
/// Use FaceBook API to share a content
print("Service: \(content) was posted to the Facebook")
}
}
class InstagramSharingService: SharingService {
func share(content: Content) {
/// Use Instagram API to share a content
print("Service: \(content) was posted to the Instagram", terminator: "\n\n")
}
}
protocol Content: CustomStringConvertible {
var title: String { get }
var images: [UIImage] { get }
}
struct FoodDomainModel: Content {
var title: String
var images: [UIImage]
var calories: Int
var description: String {
return "Food Model"
}
}
Output.txt: 执行结果
Client: Pushing Photo View Controller...
PhotoViewController: User selected a Food Model to share
Service: Food Model was posted to the Instagram
PhotoViewController: User selected a Food Model to share
Service: Food Model was posted to the Facebook
Client: Pushing Feed View Controller...
FeedViewController: User selected a Food Model to share
Service: Food Model was posted to the Instagram
FeedViewController: User selected a Food Model to share
Service: Food Model was posted to the Facebook