亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

c# 如何用組合替代繼承

 更新時(shí)間:2021年02月19日 14:41:38   作者:丹楓無(wú)跡  
這篇文章主要介紹了c# 如何用組合替代繼承,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下

如果問(wèn)面向?qū)ο蟮娜筇匦允鞘裁?,多?shù)人都能回答出來(lái):封裝、繼承、多態(tài)。

繼承 作為三大特性之一,近來(lái)卻越來(lái)越不推薦使用,更有極端的語(yǔ)言,直接語(yǔ)法中就不支持繼承,例如 Go。這又是為什么呢?

為什么不推薦使用繼承?

假設(shè)我們要設(shè)計(jì)一個(gè)關(guān)于鳥(niǎo)的類。

我們將“鳥(niǎo)類”定義為一個(gè)抽象類 AbstractBird。所有更細(xì)分的鳥(niǎo),比如麻雀、鴿子、烏鴉等,都繼承這個(gè)抽象類。

大部分鳥(niǎo)都會(huì)飛,那我們可不可以在 AbstractBird 抽象類中,定義一個(gè) Fly() 方法呢?

答案是否定的。盡管大部分鳥(niǎo)都會(huì)飛,但也有特例,比如鴕鳥(niǎo)就不會(huì)飛。鴕鳥(niǎo)繼承具有 Fly() 方法的父類,那鴕鳥(niǎo)就具有“飛”這樣的行為,這顯然不符合我們對(duì)現(xiàn)實(shí)世界中事物的認(rèn)識(shí)。

解決方案一

在鴕鳥(niǎo)這個(gè)子類中重寫(xiě) Fly() 方法,讓它拋出異常。

public class AbstractBird
{
  public virtual void Fly()
  {
    Console.WriteLine("I'm flying.");
  }
}

//鴕鳥(niǎo)
public class Ostrich : AbstractBird
{
  public override void Fly()
  {
    throw new NotImplementedException("I can't fly.");
  }
}

這種設(shè)計(jì)思路雖然可以解決問(wèn)題,但不夠優(yōu)美。因?yàn)槌锁r鳥(niǎo)之外,不會(huì)飛的鳥(niǎo)還有很多,比如企鵝。對(duì)于這些不會(huì)飛的鳥(niǎo)來(lái)說(shuō),我們都需要重寫(xiě) Fly() 方法,拋出異常。

這違背了迪米特法則(也叫最少知識(shí)原則),暴露不該暴露的接口給外部,增加了類使用過(guò)程中被誤用的概率。

解決方案二

通過(guò) AbstractBird 類派生出兩個(gè)更加細(xì)分的抽象類:會(huì)飛的鳥(niǎo)類 AbstractFlyableBird 和不會(huì)飛的鳥(niǎo)類 AbstractUnFlyableBird,讓麻雀、烏鴉這些會(huì)飛的鳥(niǎo)都繼承 AbstractFlyableBird,讓鴕鳥(niǎo)、企鵝這些不會(huì)飛的鳥(niǎo),都繼承 AbstractUnFlyableBird 類。

此時(shí),繼承關(guān)系變成了三層,還行得通。

如果要再添加一個(gè)游泳 Swim() 的方法,那情況就復(fù)雜了,要分為四中情況:

  • 會(huì)飛會(huì)游泳
  • 會(huì)飛不會(huì)游泳
  • 不會(huì)飛會(huì)游泳
  • 不會(huì)飛不會(huì)游泳

如果再有其他行為加入,抽象類的數(shù)量就會(huì)幾何級(jí)數(shù)增長(zhǎng)。

我們要搞清楚某個(gè)類具有哪些方法、屬性,必須閱讀父類的代碼、父類的父類的代碼……一直追溯到最頂層父類的代碼。

使用組合

針對(duì)“會(huì)飛”這樣一個(gè)行為特性,我們可以定義一個(gè) Flyable 接口,只讓會(huì)飛的鳥(niǎo)去實(shí)現(xiàn)這個(gè)接口。針對(duì)會(huì)游泳,定義一個(gè) Swimable 接口,會(huì)叫定義一個(gè) Tweetable 接口。

public interface Flyable
{
  void Fly();
}

public interface Swimable
{
  void Swim();
}

public interface Tweetable
{
  void Tweet();
}

//麻雀
public class Sparrow : Flyable, Tweetable
{
  public void Fly() => Console.WriteLine("I am flying.");

  public void Tweet() => Console.WriteLine("!@#$%^&*……");
}

//企鵝
public class Penguin : Swimable, Tweetable
{
  public void Swim() => Console.WriteLine("I am swimming.");

  public void Tweet() => Console.WriteLine("!@#$%^&*……");
}

麻雀和企鵝都會(huì)叫,Tweet 實(shí)現(xiàn)了兩遍,這是壞味道。我們可以用組合來(lái)消除這個(gè)壞味道。

public interface Flyable
{
  void Fly();
}

public interface Swimable
{
  void Swim();
}

public interface Tweetable
{
  void Tweet();
}

public class FlyAbility : Flyable
{
  public void Fly() => Console.WriteLine("I am flying.");
}

public class SwimAbility : Swimable
{
  public void Swim() => Console.WriteLine("I am swimming.");
}

public class TweetAbility : Tweetable
{
  public void Tweet() => Console.WriteLine("!@#$%^&*……");
}

//麻雀
public class Sparrow : Flyable, Tweetable
{
  FlyAbility flyAbility = new FlyAbility();
  TweetAbility tweetAbility = new TweetAbility();

  public void Fly() => flyAbility.Fly();

  public void Tweet() => tweetAbility.Tweet();
}

//企鵝
public class Penguin : Swimable, Tweetable
{
  SwimAbility swimAbility = new SwimAbility();
  TweetAbility tweetAbility = new TweetAbility();

  public void Swim() => swimAbility.Swim();

  public void Tweet() => tweetAbility.Tweet();
}

雖然現(xiàn)在主流的思想都是多用組合少用繼承,但是從上面的例子可以看出,繼承改寫(xiě)成組合意味著要做更細(xì)粒度的類的拆分,要定義更多的類和接口。類和接口的增多也就或多或少地增加代碼的復(fù)雜程度和維護(hù)成本。所以,在實(shí)際的項(xiàng)目開(kāi)發(fā)中,我們還是要根據(jù)具體的情況,來(lái)具體選擇該用繼承還是組合。

以上就是c# 如何用組合替代繼承的詳細(xì)內(nèi)容,更多關(guān)于c# 組合替代繼承的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論