设计模式-(6)适配器 (swift版)

用来解决接口适配问题的三种模式:适配器模式,桥接模式,外观模式。

 

一,概念

  适配器模式,将一个类的结构转换成用户希望的另一个接口,使得原本接口不兼容的类能在一起工作。换句话说,适配器模式就是链接两种不同种类的对象,使其很好的协同工作。(说的很美吧,我抄的,百度里每个帖子都会这样说。简单说就是你笔记本是19v供电,但是家里面电压是220v,这时候想要充电,就需要一个笔记本的220v转19v电源适配器)。

  有两种实现结构(类的适配器,对象的适配器),还有说三种(接口的适配器方式),额。

  

二,模式结构图

  了解三个角色,结合结构图理解:

    Target:目标角色定义客户端具体使用的接口,也就是我们的期望接口,简单一点就是协议,协议定义我们需要的接口

    Adaptee:源角色,你想把“谁”转换成目标角色,这个“谁”就是源角色,它是已经存在的、运行良好的类或对象。

    Adapter:适配器角色,适配器模式的核心角色,其他两个角色都是已经存在的角色,而适配器角色是需要新建立的,他的职责非常简单:把源角色转换为目标角色。

 

  类的适配器模式:

  

  Adapter是一个Target(目标接口)类型,同时也是一个Adaptee(被适配的类)类型。Adapter重载Target的request方法,但没有重载Adaptee的specificRequest方法,而是在其request方法中调用父类的specificRequest方法(即:[super specificRequest])。当request方法在运行时,向Adaptee发送super消息时,Adaptee按自己的方式执行specificRequest方法。注意:只有当Target是协议而不是类时,类适配器才能用Objective-C实现。

 

  对象的适配器模式:

  

  Target和Adapter之间的关系与类适配器相同,而Adapter和Adaptee之间的关系从“属于(继承)”变成了“包含(组合引用)”。这种情况下Adapter持有一个对Adaptee的引用,在request方法中,Adapter发送[adaptee specificRequest]消息,以间接方法Adaptee的specificRequest方法,然后实现客户端请求的其他部分。

 

三,使用场景:(也是copy的,多读读回忆下项目代码就能理解了)

  1:你想使用一个已经存在的类,而它的接口不符合你的需求,即已有类的接口与需求不匹配
  2:你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作
  3:(仅适用于对象Adapter)你想使用一些已存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口,对象适配器可以适配它的父类接口

 

四,Demo演示:
  下面有个场景,已经存在一个UniversulAudioPlayer类,可以进行音频的播放。但是ViewController端需要的是一个遵守了AudioPlayerProtocol协议接口的类对象 AudioPlayerProtocol协议规范了ViewController调用接口,她和UniversulAudioPlayer已经实现的接口并不匹配。代码如下:

Target

protocol AudioPlayerProtocol {
    
    /// setting media source
    ///
    /// - Parameter url: source url
    /// - Returns: whether success
    func prepareWithUrl(url: URL) -> Bool
    
    /// jump to playing time point
    ///
    /// - Parameter time: the time point 0 - media.duration
    /// - Returns: whether success
    func jumpTo(time: TimeInterval) -> Bool
    
    /// increase valume,add 0.1 once, value0 - 1
    ///
    /// - Returns: Voide
    func increaseVolume() -> Void
    
    /// reduce Volume
    ///
    /// - Returns: Void
    func reduceVolume() -> Void
    
    /// start to play the audio
    ///
    /// - Returns:
    func play() -> Void
    
    /// pause the audio
    ///
    /// - Returns:
    func pause() -> Void
    
    /// resume to play
    ///
    /// - Returns:
    func resume() -> Void
}

 Adapee

class UniversulAudioPlayer: NSObject {
    
    private var url: URL?
    private var duration: TimeInterval = 0
    private var volumeValue: Float = 0
    private var timeValue: TimeInterval = 0
    
    var volume: Float{
        set{
            if newValue <= 0 {
                self.volumeValue = 0
            }else if newValue >= 1{
                self.volumeValue = 1.0
            }else{
                self.volumeValue = newValue
            }
            print("new volume: \(self.volumeValue)")
        }
        get{
            return self.volumeValue
        }
    }
    
    var time: TimeInterval{
        set{
            if newValue >= 0.0 && newValue <= duration {
                self.timeValue = newValue
                print("new time: \(newValue)")
            }
        }
        get{
            return self.timeValue
        }
    }
    
    func audioWithUrl(url: URL) -> Bool {
        print("setting url: \(url)")
        self.duration = 300;
        self.url = url;
        return true
    }
    
    func playAudio()  {
        if url != nil {
            print("start\resume to play audio \(url!)")
        }else{
            print("play fail")
        }
    }
    
    func pauseAudio()  {
        if url != nil {
            print("pause audio \(url!)")
        }else{
            print("play fail")
        }
    }
}

 Client

class ViewController: UIViewController {

    var player: AudioPlayerProtocol!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
//        player = MyUniversulAudioPlayer()
        player = TheUniversulAudioPlayer()
        player.prepareWithUrl(url: URL(string: "http://www.y.com/music/a.mp3")!)
    }
    
    //按钮事件
    
    @IBAction func playBtnClicked(_ sender: Any) {
        player.play()
    }

    @IBAction func pauseBtnClicked(_ sender: Any) {
        player.pause()
    }
    
    @IBAction func resumeBtnClicked(_ sender: Any) {
        player.resume()
    }
    
    @IBAction func increaseVolumeBtnClicked(_ sender: Any) {
        player.increaseVolume()
    }
    
    @IBAction func reduceVolumeBtnClicked(_ sender: Any) {
        player.reduceVolume()
    }
    
}

 所以,就需要我们做一个适配器
1,类的适配器模式:

class MyUniversulAudioPlayer: UniversulAudioPlayer, AudioPlayerProtocol {
    func prepareWithUrl(url: URL) -> Bool {
        return super.audioWithUrl(url: url)
    }
    
    func jumpTo(time: TimeInterval) -> Bool {
        super.time = time
        return true
    }
    
    func increaseVolume() {
        self.volume += 0.1
    }
    
    func reduceVolume() {
        self.volume -= 0.1
    }
    
    func play() {
        self.playAudio()
    }
    
    func pause() {
        self.pauseAudio()
    }
    
    func resume() {
        self.playAudio()
    }
    
    
}

 2,对象的适配器模式

class TheUniversulAudioPlayer: AudioPlayerProtocol {
    
    private var universulPlayer = UniversulAudioPlayer()
    
    func prepareWithUrl(url: URL) -> Bool {
        return universulPlayer.audioWithUrl(url: url)
    }
    
    func jumpTo(time: TimeInterval) -> Bool {
        universulPlayer.time = time
        return true
    }
    
    func increaseVolume() {
        universulPlayer.volume += 0.1
    }
    
    func reduceVolume() {
        universulPlayer.volume -= 0.1
    }
    
    func play() {
        universulPlayer.playAudio()
    }
    
    func pause() {
        universulPlayer.pauseAudio()
    }
    
    func resume() {
        universulPlayer.playAudio()
    }
    
    
}

 

  

posted on 2018-03-29 18:00  洋子哥哥  阅读(290)  评论(0编辑  收藏  举报