1. 程式人生 > >移動開發之設計模式-介面卡模式(IOS&Android)

移動開發之設計模式-介面卡模式(IOS&Android)

資源

完全參照 組合模式|菜鳥教程 ,但不包括IOS程式碼

介面卡模式

介面卡模式(Adapter Pattern)是作為兩個不相容的介面之間的橋樑。這種型別的設計模式屬於結構型模式,它結合了兩個獨立介面的功能。
這種模式涉及到一個單一的類,該類負責加入獨立的或不相容的介面功能。舉個真實的例子,讀卡器是作為記憶體卡和筆記本之間的介面卡。您將記憶體卡插入讀卡器,再將讀卡器插入筆記本,這樣就可以通過筆記本來讀取記憶體卡。
我們通過下面的例項來演示介面卡模式的使用。其中,音訊播放器裝置只能播放 mp3 檔案,通過使用一個更高階的音訊播放器來播放 vlc 和 mp4 檔案。

資源

意圖: 將一個類的介面轉換成客戶希望的另外一個介面。介面卡模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。
主要解決: 主要解決在軟體系統中,常常要將一些"現存的物件"放到新的環境中,而新環境要求的介面是現物件不能滿足的。
何時使用:
1、系統需要使用現有的類,而此類的介面不符合系統的需要。
2、想要建立一個可以重複使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作,這些源類不一定有一致的介面。
3、通過介面轉換,將一個類插入另一個類系中。(比如老虎和飛禽,現在多了一個飛虎,在不增加實體的需求下,增加一個介面卡,在裡面包容一個虎物件,實現飛的介面。)

如何解決:繼承或依賴(推薦)。
關鍵程式碼:介面卡繼承或依賴已有的物件,實現想要的目標介面。
應用例項:
1、美國電器 110V,中國 220V,就要有一個介面卡將 110V 轉化為 220V。
2、JAVA JDK 1.1 提供了 Enumeration 介面,而在 1.2 中提供了 Iterator 介面,想要使用 1.2 的 JDK,則要將以前系統的 Enumeration 介面轉化為 Iterator 介面,這時就需要介面卡模式。
3、在 LINUX 上執行 WINDOWS 程式。
4、JAVA 中的 jdbc。

優點:
1、可以讓任何兩個沒有關聯的類一起執行。
2、提高了類的複用。
3、增加了類的透明度。
4、靈活性好。

缺點:
1、過多地使用介面卡,會讓系統非常零亂,不易整體進行把握。比如,明明看到呼叫的是 A 介面,其實內部被適配成了 B 介面的實現,一個系統如果太多出現這種情況,無異於一場災難。因此如果不是很有必要,可以不使用介面卡,而是直接對系統進行重構。
2.由於 JAVA 至多繼承一個類,所以至多隻能適配一個適配者類,而且目標類必須是抽象類。

使用場景:有動機地修改一個正常執行的系統的介面,這時應該考慮使用介面卡模式。
注意事項:介面卡不是在詳細設計時新增的,而是解決正在服役的專案的問題。

實現

我們有一個 MediaPlayer 介面和一個實現了 MediaPlayer 介面的實體類 AudioPlayer。預設情況下,AudioPlayer 可以播放 mp3 格式的音訊檔案。
我們還有另一個介面 AdvancedMediaPlayer 和實現了 AdvancedMediaPlayer 介面的實體類。該類可以播放 vlc 和 mp4 格式的檔案。
我們想要讓 AudioPlayer 播放其他格式的音訊檔案。為了實現這個功能,我們需要建立一個實現了 MediaPlayer 介面的介面卡類 MediaAdapter,並使用 AdvancedMediaPlayer 物件來播放所需的格式。
AudioPlayer 使用介面卡類 MediaAdapter 傳遞所需的音訊型別,不需要知道能播放所需格式音訊的實際類。AdapterPatternDemo,我們的演示類使用 AudioPlayer 類來播放各種格式。

Android

MediaPlayer.java

public interface MediaPlayer {
   public void play(String audioType, String fileName);
}

AdvanceMediaPlayer.java

public interface AdvancedMediaPlayer { 
   public void playVlc(String fileName);
   public void playMp4(String fileName);
}

VlcPlayer.java

public class VlcPlayer implements AdvancedMediaPlayer{
   @Override
   public void playVlc(String fileName) {
      System.out.println("Playing vlc file. Name: "+ fileName);      
   }
 
   @Override
   public void playMp4(String fileName) {
      //什麼也不做
   }
}

Mp4Player.java

public class Mp4Player implements AdvancedMediaPlayer{
 
   @Override
   public void playVlc(String fileName) {
      //什麼也不做
   }
 
   @Override
   public void playMp4(String fileName) {
      System.out.println("Playing mp4 file. Name: "+ fileName);      
   }
}

MediaAdapter.java

public class MediaAdapter implements MediaPlayer {
 
   AdvancedMediaPlayer advancedMusicPlayer;
 
   public MediaAdapter(String audioType){
      if(audioType.equalsIgnoreCase("vlc") ){
         advancedMusicPlayer = new VlcPlayer();       
      } else if (audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer = new Mp4Player();
      }  
   }
 
   @Override
   public void play(String audioType, String fileName) {
      if(audioType.equalsIgnoreCase("vlc")){
         advancedMusicPlayer.playVlc(fileName);
      }else if(audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer.playMp4(fileName);
      }
   }
}

AudioPlayer.java

public class AudioPlayer implements MediaPlayer {
   MediaAdapter mediaAdapter; 
 
   @Override
   public void play(String audioType, String fileName) {    
 
      //播放 mp3 音樂檔案的內建支援
      if(audioType.equalsIgnoreCase("mp3")){
         System.out.println("Playing mp3 file. Name: "+ fileName);         
      } 
      //mediaAdapter 提供了播放其他檔案格式的支援
      else if(audioType.equalsIgnoreCase("vlc") 
         || audioType.equalsIgnoreCase("mp4")){
         mediaAdapter = new MediaAdapter(audioType);
         mediaAdapter.play(audioType, fileName);
      }
      else{
         System.out.println("Invalid media. "+
            audioType + " format not supported");
      }
   }   
}

AdapterPatternDemo.java

public class AdapterPatternDemo {
   public static void main(String[] args) {
      AudioPlayer audioPlayer = new AudioPlayer();
 
      audioPlayer.play("mp3", "beyond the horizon.mp3");
      audioPlayer.play("mp4", "alone.mp4");
      audioPlayer.play("vlc", "far far away.vlc");
      audioPlayer.play("avi", "mind me.avi");
   }
}

結果

Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name: alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported

IOS

AdvancedMediaPlayer.h

@protocol AdvancedMediaPlayer <NSObject>
-(void) playVlc:(NSString*) fileName;
-(void) playMp4:(NSString*) fileName;
@end

MediaPlayer.h

@protocol MediaPlayer <NSObject>
-(void)play:(NSString*)audioType fileName:(NSString*)fileName;
@end

VlcPlayer.h

#import <Foundation/Foundation.h>
#import "AdvancedMediaPlayer.h"

@interface VlcPlayer : NSObject <AdvancedMediaPlayer>
-(void) playVlc:(NSString*) fileName;
-(void) playMp4:(NSString*) fileName;
@end

VlcPlayer.m

#import "VlcPlayer.h"
#import "AdvancedMediaPlayer.h"
@interface VlcPlayer () 
@end
@implementation VlcPlayer
- (void)playMp4:(NSString *)fileName {
    //什麼也不做
}
- (void)playVlc:(NSString *)fileName {
    NSLog(@"Playing vlc file. Name: %@", fileName);
}
@end

Mp4Player.h

#import <Foundation/Foundation.h>
#import "AdvancedMediaPlayer.h"

@interface Mp4Player : NSObject <AdvancedMediaPlayer>
-(void) playVlc:(NSString*) fileName;
-(void) playMp4:(NSString*) fileName;
@end

Mp4Player.m

#import "Mp4Player.h"
#import "AdvancedMediaPlayer.h"
@interface Mp4Player () 
@end
@implementation Mp4Player
- (void)playMp4:(NSString *)fileName {
    NSLog(@"Playing mp4 file. Name:%@", fileName);
}
- (void)playVlc:(NSString *)fileName {
    //什麼也不做
}
@end

MediaAdapter.h


#import <Foundation/Foundation.h>
#import "MediaPlayer.h"

@interface MediaAdapter : NSObject <MediaPlayer>
-(instancetype)initWithAudioType:(NSString*)aduioType;
-(void)play:(NSString*)audioType fileName:(NSString*)fileName;
@end

MediaAdapter.m

#import "MediaAdapter.h"
#import "MediaPlayer.h"
#import "VlcPlayer.h"
#import "Mp4Player.h"
#import "AdvancedMediaPlayer.h"

@interface MediaAdapter()
@property (nonatomic, strong) id <AdvancedMediaPlayer> advancedMusicePlayer;
@end
@implementation MediaAdapter

- (instancetype)initWithAudioType:(NSString *)aduioType{
    self = [super init];
    if(self) {
        if([aduioType isEqualToString:@"vlc"]){
            self.advancedMusicePlayer =  [[VlcPlayer alloc]init];
        } else if([aduioType isEqualToString:@"mp4"]) {
            self.advancedMusicePlayer = [[Mp4Player alloc] init];
        }
    }
    return self;
}

- (void)play:(NSString *)audioType fileName:(NSString *)fileName {
    if([audioType isEqualToString:@"vlc"]) {
        [self.advancedMusicePlayer playVlc:fileName];
    } else if([audioType isEqualToString:@"mp4"]) {
        [self.advancedMusicePlayer playMp4:fileName];
    }
}

@end

AudioPlayer.h


#import <Foundation/Foundation.h>
#import "MediaPlayer.h"
@interface AudioPlayer : NSObject <MediaPlayer>
- (void)play:(NSString *)audioType fileName:(NSString *)fileName;
@end

AudioPlayer.m

#import "AudioPlayer.h"
#import "MediaAdapter.h"
@interface AudioPlayer()
@property (nonatomic, strong) MediaAdapter *mediaAdapter;
@end
@implementation AudioPlayer

- (void)play:(NSString *)audioType fileName:(NSString *)fileName {
    //播放mp3音樂檔案的內建支援
    if([audioType isEqualToString:@"mp3"]) {
        NSLog(@"Playing mp3 file. Name: %@", fileName);
    }
    //mediaPlayer提供了播放其他檔案格式的支援
    else if([audioType isEqualToString:@"vlc"] || [audioType isEqualToString:@"mp4"]) {
        self.mediaAdapter = [[MediaAdapter alloc]initWithAudioType:audioType];
        [self.mediaAdapter play:audioType fileName:fileName];
    }
    else {
        NSLog(@"Invalid media. %@ format not supported.", audioType);
    }
}

@end

結果

Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name:alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported.