iT邦幫忙

2023 iThome 鐵人賽

DAY 6
0
自我挑戰組

初階面試常見題目彙整系列 第 6

初階面試常見題目回答-介面-鐵人賽第六日

  • 分享至 

  • xImage
  •  

一生二,二生三,三生萬物
在昨日描述的途中,
提過了何謂抽象
我把它描述成廣義的定義。

那麼函式多載會是同名的但不同實作的Function,
如果我把多型與抽象結合起來會是什麼樣子。

就是多型裡面,
還有一個常常被提到的,
筆者認為值得單獨拿出來再次訴說的。

介面(interface)

關於介面當初被問的時候,
筆者回答得還蠻搞笑的,
我記憶的很朦朧,
就是一對多,
回來一樣的。

不能說不對,但大家知道的,
面試官都不知道聽幾人面試了,
這種回答不會太好。

那麼回到介面的定義
指的是一種抽象的定義,用來規定一個類別或對象應該實現哪些方法或功能,而不關心具體的實現細節。

其實就以定義來說,
我會認為他要說成是多型的封裝也不為過,
簡單來說就是提供同樣的規格給他人使用,
最常被拿來譬喻的就是USB了。

而介面有幾個常見的使用地方,
這邊先用之前說過的例子作為案例,
在前幾日的多型中,
筆者有提供一個移動的程式碼,
但這個會有一個問題,
逐漸越來越多多型會造成可供使用的參數越來越少,
這時候就可以透過介面把從橫向發展的程式,
用成有階層狀似的。

public class MoveModel
{
    //載具,假定汽車
    public void Move(int Gasoline)
    {
        #region 流程

        if (Gasoline >= 1)
        {
            Console.WriteLine("Car is moving.");
            Gasoline--;
        }
        else
        {
            Console.WriteLine("Car is out of fuel.");
        }
        #endregion 流程
    }

    //人力載具,假定腳踏車
    public void Move(int humanity, double cal)
    {
        #region 流程

        if (humanity >= 1 && cal >= 1)
        {
            Console.WriteLine("Bicycle is moving.");
            humanity--;
            cal -= 1;
        }
        else
        {
            Console.WriteLine("Bicycle cannot move.");
        }
        #endregion 流程
    }

    //單純以人力移動,假定走路
    public void Move(double cal)
    {
        #region 流程
        if (cal >= 1)
        {
            Console.WriteLine("Human is moving.");
            cal -= 1;
        }
        else
        {
            Console.WriteLine("Human does not have enough energy to move.");
        }
        #endregion 流程
    }
}

在這裡製作出上層的介面,
把同樣的操作Move提取到上面,
供底下使用。

    // 定義移動介面
    public interface IMovable
    {
        void Move();
    }

    // 汽車類別實現IMovable介面
    public class Car : IMovable
    {
        private int Gasoline;

        public Car(int initialGasoline)
        {
            Gasoline = initialGasoline;
        }

        public void Move()
        {
            #region 流程

            if (Gasoline >= 1)
            {
                Console.WriteLine("Car is moving.");
                Gasoline--;
            }
            else
            {
                Console.WriteLine("Car is out of fuel.");
            }
            #endregion 流程
        }
    }

    // 腳踏車類別實現IMovable介面
    public class Bicycle : IMovable
    {
        private int humanity;
        private double cal;

        public Bicycle(int initialHumanity, double initialCal)
        {
            humanity = initialHumanity;
            cal = initialCal;
        }

        public void Move()
        {
            #region 流程

            if (humanity >= 1 && cal >= 1)
            {
                Console.WriteLine("Bicycle is moving.");
                humanity--;
                cal -= 1;
            }
            else
            {
                Console.WriteLine("Bicycle cannot move.");
            }
            #endregion 流程
        }
    }

    // 人類類別實現IMovable介面
    public class Human : IMovable
    {
        private double cal;

        public Human(double initialCal)
        {
            cal = initialCal;
        }

        public void Move()
        {
            if (cal >= 1)
            {
                Console.WriteLine("Human is moving.");
                cal -= 1;
            }
            else
            {
                Console.WriteLine("Human does not have enough energy to move.");
            }
        }
    }

那麼就可以供其他類別去使用,
如同樣是使用汽油的airplane,
就不會因為想要使用同樣的參數而無法操作。

那麼在這裡大致介紹過一輪,
多型如何轉成介面,
當然可能這個例子,
這個介面看起來有點多餘。

那麼除此之外,
有一個最常見的狀況,
透過不同的傳入,
卻要求一樣class的回傳,
就像是根據供應商,卻查找對應資訊一樣,
如同前面我常常用汽車來做介紹,
那這邊同樣利用汽車來舉個例子。

假設有一個汽車銷售商,
會從各個車廠中進了各種車子,
每一次去取得某種廠牌的車子都得去調資料。

Get法拉利CarData
Get三陽CarData
GetTSLACarData

但這位汽車銷售商毫不關心到底是法拉利、三陽、富豪還是什麼車廠,
每一次為了某個廠牌的詳細資料,
都要特定專門去設計一份表格,
設置有類似的欄位但指的東西不一樣,
把詳細資料拿給客戶看,
顧客無非看的東西就那幾項。

這時候汽車銷售商就想到了,
拿到各個車廠的詳細資料,
但不代表著需要整個都寫出來,
為何不拿統一的描述給眾人看呢?。

每一輛車絕大多數的人只關心,
Local、價格、馬力、初始加速度等等的,
只要把這些資料解析,組成同樣的規格,不就可以共用而且簡潔

----描述結束,
那麼我們這邊要怎麼達成這個樣子呢?

//首先,先透過傳進來的Local,查找到對應的供應商
var lHotelItineraryService = new SupplierServiceBuilder().GetCarInfomationService(Local);

//接著根據查到的資訊進入介面
lHotelItineraryService.GetCarInfomation(model);

//根據查到的資訊準備轉到具體細節
public interface ICarInfomationService
{
	/// <summary>
	/// 取得供應商訂單資訊
	/// </summary>
	/// <param name="pBookingForm"></param>
	/// <returns></returns>
	CarInfomationModel GetCarInfomation(object pBookingForm);
}

//經過具體細節後,得到CarInfomationModel,把該值放入回傳,就這樣,就定義出統一標準,

#region GetCarInfomation
public CarInfomationModel GetCarInfomation(object model)
{
	#region 宣告
	string Local = string.Empty;
	CarInfomationModel result = null;
	#endregion 宣告

	#region 流程

	#region 取得供應商資訊
	var lHotelItineraryService = new SupplierServiceBuilder().GetCarInfomationService(Local);

	if (lHotelItineraryService != null)
	{
		result = lHotelItineraryService.GetCarInfomation(model);
	}

	return result;
	#endregion 取得供應商資訊

	#endregion 流程
}
#endregion

//完整程式碼 筆者所寫簡易範例
https://github.com/LionChad/Car/blob/master/Model/GetCarInfomationModel.cs

可以看到它定義了一組方法和屬性的合同,要求實現它的類別提供這些方法和屬性的具體實現,
筆者在取得他的時候,也確實會達成既定的定義,
這就是interface所想要達成的,統一規格。

關於介面我也很喜歡用USB來介紹,以下的前輩分享也是透過USB來作為譬喻,歡迎去看看。
[物件導向] 何謂介面(interface)?
http://benyi.logdown.com/posts/2018/02/11/oop-what-is-interface


上一篇
初階面試常見題目回答-OOP物件導向概念-鐵人賽第五日
下一篇
初階面試常見題目回答-SOLID(SRP)-鐵人賽第七日
系列文
初階面試常見題目彙整30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言