--- tags: Structural Patterns --- # 轉接器模式 Adapter ## 架構圖 ![](https://i.imgur.com/ytad2im.png) ### 角色 ## 目的 1. 想利用現有的class,但它的介面卻與你所需要的不符。 2. 想做一個可再利用的class,且能與其他毫不相關、甚至尚未出現的class搭配使用,也就是說,想與介面未必相容的class合作無間。 3. 想用一些現有的sub-class,雖然介面不相容,但又不適合一個個再去衍生sub-class修改介面。Adapter可以幫忙轉換它們的super-class。 ## 比較 ### Class Adapter * 綁死在實體adaptee類別上。 * 可以覆寫adaptee的某些行為。 * 只引入一個物件個體。 * 不能在Runtime時轉換adaptee的類別。 ### Object Adapter * 不會綁死在adaptee類別上。 * 可能會引入adaptee的子類別用以覆寫行為(但不是覆寫adaptee本身)。 * 引入多個物件個體。 * 可以在Runtime時轉換adaptee的類別。 * 可以透過衍生sub-adaptee子類別向adaptee增加新功能。 ```java= //Adaptee public interface AdvancedMediaPlayer { public void playVlc(String fileName); public void playMp4(String fileName); } //Concrete Adaptee public class VlcPlayer implements AdvancedMediaPlayer{ @Override public void playVlc(String fileName) { // TODO Auto-generated method stub System.out.println("Playing vlc file. Name: "+ fileName); } @Override public void playMp4(String fileName) { // TODO Auto-generated method stub } } //Concrete Adaptee public class Mp4Player implements AdvancedMediaPlayer{ @Override public void playVlc(String fileName) { // TODO Auto-generated method stub } @Override public void playMp4(String fileName) { // TODO Auto-generated method stub System.out.println("Playing mp4 file. Name: "+ fileName); } } //Adapter public class AudioPlayer implements MediaPlayer { MediaAdapter mediaAdapter; @Override public void play(String audioType, String fileName) { // TODO Auto-generated method stub // inbuilt support to play mp3 music files if (audioType.equalsIgnoreCase("mp3")) { System.out.println("Playing mp3 file. Name: " + fileName); } // mediaAdapter is providing support to play other file formats 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"); } } } ``` In this following ex, use * Duck as a target * Turkey as a adaptee * TurkeyAdator as a adaptor suppose we r now need to pretend turkey as a duck, then use TurkeyAdator if the client want duck to quack(), it will call turkey gobble(), if the client want duck to walk, it will call turkey fly() client think that it's interact with the duck, but actually, there is a turkey behind the duck skin interact with the user :P code: ``` java // target public interface Duck { public void quack(); public void fly(); } // concrete target public class MallardDuck implements Duck { @Override public void quack() { System.out.println("Quack"); } @Override public void fly() { System.out.println("I'm flying"); } } // adaptee public interface Turkey { public void gobble(); public void fly(); } // concrete adaptee public class WildTurkey implements Turkey { @Override public void gobble() { System.out.println("Gobble gobble"); } @Override public void fly() { System.out.println("I'm flying a short distance"); } } // adaptor public class TurkeyAdapter implements Duck { private Turkey mTurkey; public TurkeyAdapter(Turkey turkey) { mTurkey = turkey; } @Override public void quack() { mTurkey.gobble(); } @Override public void fly() { mTurkey.fly(); } } ```