Design Pattern in iOS… Structural Pattern Parte 1

 

Ciao a tutti cari amici di iProg, in questo secondo articolo andremo ad esaminare gli Structural Pattern, questi pattern sono relativi a come classi e oggetti sono composti per formare strutture più grandi/complesse.

Adapter Pattern

Il fine dell’adapter è di fornire una soluzione astratta al problema dell’interoperabilità tra interfacce differenti. Il problema si presenta ogni qual volta nel progetto di un software si debbano utilizzare sistemi di supporto (come per esempio librerie) la cui interfaccia non è perfettamente compatibile con quanto richiesto da applicazioni già esistenti. Invece di dover riscrivere parte del sistema, compito oneroso e non sempre possibile se non si ha a disposizione il codice sorgente, può essere comodo scrivere un adapter che faccia da tramite. (Wikipedia)
In parole semplici questo pattern consente a oggetti incompatibili di lavorare insieme, quindi si crea una sorta di “adattatore” che permette questi due oggetti di cooperare. Questo pattern e’ utile quando abbiamo a che fare con SDK esterni che spesso non sono direttamente modificabili quindi e’ necessario creare un adapter. Vediamo ora un esempio pratico.

protocol MediaPlayer {
    func play(audioType: String, filename: String)
}

protocol AdvancedMediaPlayer {
    func playVlc(fileName: String)
    func playMp4(fileName: String)
}

class VlcPlayer: AdvancedMediaPlayer {
    func playVlc(fileName: String) {
        print("Playing vlc file. Name \(fileName)")
    }
    func playMp4(fileName: String){
        //
    }
}

class Mp4Player: AdvancedMediaPlayer {
    func playVlc(fileName: String) {
        //
    }
    func playMp4(fileName: String){
        print("Playingmp4 file. Name: \(fileName)")
    }
}

Come possiamo notare la classe VlcPlayer non puo’ riprodurre i file mp4 e la classe mp4 non puo’ riprodurre i file VLC inoltrte in questo modo non sono nemmeno scalabile andiamo a veder come risolvere questi problemi:

class MediaAdapter: MediaPlayer {
    private var advancedMusicPlayer: AdvancedMediaPlayer!
    private let audioType: String
    init(audioType: String) {
        self.audioType = audioType
        if audioType.contains("vlc") { advancedMusicPlayer = VlcPlayer() }
        else if audioType.contains("mp4") { advancedMusicPlayer = Mp4Player() }
    }
    func play(audioType: String, filename: String) {
        if audioType.contains("vlc") { advancedMusicPlayer.playVlc(fileName: filename) }
        else if audioType.contains("mp4") { advancedMusicPlayer.playMp4(fileName: filename) }
    }
}

class  AudioPlayer: MediaPlayer {
    private var mediaAdapter: MediaAdapter!
    
    func play(audioType: String, filename: String) {
        if audioType.contains("mp3") { print("Playing mp3 file. Name: \(filename)") }
        else if audioType.contains("mp4") || audioType.contains("vlc") {
            mediaAdapter = MediaAdapter(audioType: audioType)
            mediaAdapter.play(audioType: audioType, filename: filename)
        }
        else{ print("Format not supported") }
    }
}

Composite Pattern

Questo pattern permette di trattare un gruppo di oggetti come se fossero l’istanza di un oggetto singolo. Il design pattern Composite organizza gli oggetti in una struttura ad albero, nella quale i nodi sono delle composite e le foglie sono oggetti semplici.
È utilizzato per dare la possibilità ai client di manipolare oggetti singoli e composizioni in modo uniforme.

class Employee {
    let nome: String
    let dipartimento:String
    var subbordinati = [Employee]()
    init(nome:String,dipartimento:String) {
        self.nome = nome
        self.dipartimento = dipartimento
    }
    
    func add(employee: Employee) {
        self.subbordinati.append(employee)
    }
    func remove(employee: Employee ){
        if let index = subbordinati.index(where: {return $0.nome == employee.nome}) {
            self.subbordinati.remove(at: index)
        }
    }
    func getSubbordinati() -> [Employee] {
        return subbordinati
    }
}

        let ceo = Employee(nome: "Giorgio", dipartimento: "Ceo")
        let capoMarketing = Employee(nome: "Gianni", dipartimento: "Capo Marketing")
        let dipendente1 = Employee(nome: "Giuseppe", dipartimento: "Marketing")
        let dipendente2 = Employee(nome: "Nicola", dipartimento: "Marketing")
        ceo.add(employee: capoMarketing)
        capoMarketing.add(employee: dipendente1)
        capoMarketing.add(employee: dipendente2)
        
        //Print organizzazione
        for capo in ceo.getSubbordinati() {
            print(capo.nome)
            for dipendente in capoMarketing.getSubbordinati() {
                print(dipendente.nome)
            }
        }

Nel prossimo tutorial continueremo ad esplorare gli Structural Pattern