Java設計模式面試題2則
【題目-1】Windows Media Player和RealPlayer是常用的媒體播放器,它們的API結構和呼叫方法非常不同,現在你的應用需要同時支援呼叫這2種播放器的API。你要怎麼設計?
【分析】明顯應該採用Adapter模式,將播放器的同類型API進行分類,對於播放器某一些同類型的API(比如畫面調節),定義MediaPlayerClassA和RealPlayerClassA都實現了IMediaA介面。MediaPlayerClassA呼叫MediaPlayer的APIs來實現IMediaA介面定義的功能;RealPlayerClassA則呼叫RealPlayer APIs。
對另外一些類似的
依次類推……
在建立這些同類型的MediaPlayerClassA和RealPlayerClassA,MediaPlayerClassB和RealPlayerClassB……的時候考慮使用工廠方法,一類API定義一個工廠類,這其實是抽象工廠方法。定義介面MediaFactoryAPI型別,MediaPlayerFactory和RealPlayerFactory實現該介面,MediaPlayerFactory建立MediaPlayer產品族,即MediaPlayerClassA
所以總的模式是“Adapter+Factory”。左邊是介面卡模式,右邊是工廠模式(抱歉不太會畫UM,線上畫圖工具)
<span style="font-weight: normal;">IMediaA iMediaA=AllFactory.createMediaPlayFactory().produceClassA(); iMediaA.fixPicture(); IMediaA iMediaA2= AllFactory.createRealPlayerFactory().produceClassA(); iMediaA2.fixPicture();</span>
……
Java模擬:
比如Windows Media Player和RealPlayer各自有一類調整畫面的API,標記為第A類:
<span style="font-weight: normal;">/**
* 建立時間:2014年9月9日 下午4:39:29
* 專案名稱:Test
* @author Cao Yanfeng
* @since JDK 1.6.0_21
* 類說明:
*/
public class MediaPlayer {
public void pictureAdjust() {
System.out.println("picure is adjusting……");
}
}
/**
* 建立時間:2014年9月9日 下午4:39:41
* 專案名稱:Test
* @author Cao Yanfeng
* @since JDK 1.6.0_21
* 類說明:
*/
/**
* @author Yanfeng Cao
*
*/
public class RealPlayer {
public void adjustPicture() {
System.out.println("adjusting picure……");
}
}</span>
<span style="font-weight: normal;">/**
* 建立時間:2014年9月9日 下午4:42:58
* 專案名稱:Test
* @author Cao Yanfeng
* @since JDK 1.6.0_21
* 類說明:
*/
public interface IMediaA {
public void fixPicture();
}</span>
第二步:根據Adapter模式,生成我自己的API類
<span style="font-weight: normal;">/**
* 建立時間:2014年9月9日 下午4:38:54
* 專案名稱:Test
* @author Cao Yanfeng
* @since JDK 1.6.0_21
* 類說明: 物件的介面卡模式
*/
public class MediaPlayerClassA implements IMediaA{
private MediaPlayer mediaPlayer;
/**
*
*/
public MediaPlayerClassA(MediaPlayer mediaPlayer) {
// TODO Auto-generated constructor stub
this.mediaPlayer=mediaPlayer;
}
@Override
public void fixPicture() {
// TODO Auto-generated method stub
mediaPlayer.pictureAdjust();
}
}
/**
* 建立時間:2014年9月9日 下午4:39:16
* 專案名稱:Test
* @author Cao Yanfeng
* @since JDK 1.6.0_21
* 類說明:
*/
public class RealPlayerClassA implements IMediaA{
private RealPlayer realPlayer;
/**
*
*/
public RealPlayerClassA(RealPlayer realPlayer) {
// TODO Auto-generated constructor stub
this.realPlayer=realPlayer;
}
@Override
public void fixPicture() {
// TODO Auto-generated method stub
realPlayer.adjustPicture();
}
}</span>
第三步:生成產生以上兩個類的工廠介面和工廠類,這是抽象工廠模式
<span style="font-weight: normal;">/**
* 建立時間:2014年9月9日 下午4:55:28
* 專案名稱:Test
* @author Cao Yanfeng
* @since JDK 1.6.0_21
* 類說明:
*/
public interface MediaFactory {
public IMediaA produceClassA();
}
/**
* 建立時間:2014年9月9日 下午4:57:14
* 專案名稱:Test
* @author Cao Yanfeng
* @since JDK 1.6.0_21
* 類說明: 抽象工廠模式
*/
public class MediaPlayFactory implements MediaFactory {
/* (non-Javadoc)
* @see cn.geosis.mode.Factory#produceClassA()
*/
@Override
public IMediaA produceClassA() {
// TODO Auto-generated method stub
return new MediaPlayerClassA(new MediaPlayer());
}
}
/**
* 建立時間:2014年9月9日 下午4:58:38
* 專案名稱:Test
* @author Cao Yanfeng
* @since JDK 1.6.0_21
* 類說明: 抽象工廠模式
*/
public class RealPlayerFactory implements MediaFactory {
/* (non-Javadoc)
* @see cn.geosis.mode.Factory#produceClassA()
*/
@Override
public IMediaA produceClassA() {
// TODO Auto-generated method stub
return new RealPlayerClassA(new RealPlayer());
}
}</span>
第四步:用一個靜態工廠模式生成以上兩個工廠類
<span style="font-weight: normal;">/**
* 建立時間:2014年9月9日 下午5:04:08
* 專案名稱:Test
* @author Cao Yanfeng
* @since JDK 1.6.0_21
* 類說明: 靜態工廠模式
*/
public class AllFactory{
public static MediaPlayFactory createMediaPlayFactory() {
return new MediaPlayFactory();
}
public static RealPlayerFactory createRealPlayerFactory() {
return new RealPlayerFactory();
}
}</span>
測試:
<span style="font-weight: normal;">/**
* 建立時間:2014年9月9日 下午5:08:53
* 專案名稱:Test
* @author Cao Yanfeng
* @since JDK 1.6.0_21
* 類說明:
*/
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
IMediaA iMediaA=AllFactory.createMediaPlayFactory().produceClassA();
iMediaA.fixPicture();
IMediaA iMediaA2=AllFactory.createRealPlayerFactory().produceClassA();
iMediaA2.fixPicture();
}
}</span>
****************************************************************
對於B類的APIs,例如調整音量,需要定義介面ImediaB,採用介面卡模式生成MediaPlayerClassB和RealPlayerClassB,在以上的工廠介面MediaFactory中加入public IMediaB produceClassB(),在以上的兩個工廠方法中加入public IMediaB produceClassB()方法即完成了B類APIs的新增,呼叫過程:
<span style="font-weight: normal;"> IMediaB iMediaB=AllFactory.createMediaPlayFactory().produceClassB();
iMediaB.fixVolume();</span>
【題目—2】現在有一種空調,它支援3種模式:Hot Air,Cool Air 和DoNothing。例如,當選擇Hot Air模式時,再選擇溫度為20度,空調將輸送熱風;選擇 Cool Air模式,溫度設定為20度時,將輸送冷風;在選擇DoNothing模式時,空調什麼都不做。你將考慮如何為空調設計應用程式?如果將來空調需要增加支援新的模式呢?】
【分析】參考中說是用享元模式,應該是不合適的,我認為應該用狀態模式(State)。