服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - c# 如何用组合替代继承

c# 如何用组合替代继承

2022-11-01 14:59丹枫无迹 C#

这篇文章主要介绍了c# 如何用组合替代继承,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下

如果问面向对象的三大特性是什么,多数人都能回答出来:封装、继承、多态。

继承 作为三大特性之一,近来却越来越不推荐使用,更有极端的语言,直接语法中就不支持继承,例如 Go。这又是为什么呢?

为什么不推荐使用继承?

假设我们要设计一个关于鸟的类。

我们将“鸟类”定义为一个抽象类 AbstractBird。所有更细分的鸟,比如麻雀、鸽子、乌鸦等,都继承这个抽象类。

大部分鸟都会飞,那我们可不可以在 AbstractBird 抽象类中,定义一个 Fly() 方法呢?

答案是否定的。尽管大部分鸟都会飞,但也有特例,比如鸵鸟就不会飞。鸵鸟继承具有 Fly() 方法的父类,那鸵鸟就具有“飞”这样的行为,这显然不符合我们对现实世界中事物的认识。

解决方案一

在鸵鸟这个子类中重写 Fly() 方法,让它抛出异常。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class AbstractBird
{
  public virtual void Fly()
  {
    Console.WriteLine("I'm flying.");
  }
}
 
//鸵鸟
public class Ostrich : AbstractBird
{
  public override void Fly()
  {
    throw new NotImplementedException("I can't fly.");
  }
}

这种设计思路虽然可以解决问题,但不够优美。因为除了鸵鸟之外,不会飞的鸟还有很多,比如企鹅。对于这些不会飞的鸟来说,我们都需要重写 Fly() 方法,抛出异常。

这违背了迪米特法则(也叫最少知识原则),暴露不该暴露的接口给外部,增加了类使用过程中被误用的概率。

解决方案二

通过 AbstractBird 类派生出两个更加细分的抽象类:会飞的鸟类 AbstractFlyableBird 和不会飞的鸟类 AbstractUnFlyableBird,让麻雀、乌鸦这些会飞的鸟都继承 AbstractFlyableBird,让鸵鸟、企鹅这些不会飞的鸟,都继承 AbstractUnFlyableBird 类。

此时,继承关系变成了三层,还行得通。

如果要再添加一个游泳 Swim() 的方法,那情况就复杂了,要分为四中情况:

  • 会飞会游泳
  • 会飞不会游泳
  • 不会飞会游泳
  • 不会飞不会游泳

如果再有其他行为加入,抽象类的数量就会几何级数增长。

我们要搞清楚某个类具有哪些方法、属性,必须阅读父类的代码、父类的父类的代码……一直追溯到最顶层父类的代码。

使用组合

针对“会飞”这样一个行为特性,我们可以定义一个 Flyable 接口,只让会飞的鸟去实现这个接口。针对会游泳,定义一个 Swimable 接口,会叫定义一个 Tweetable 接口。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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("!@#$%^&*……");
}

麻雀和企鹅都会叫,Tweet 实现了两遍,这是坏味道。我们可以用组合来消除这个坏味道。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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();
}

虽然现在主流的思想都是多用组合少用继承,但是从上面的例子可以看出,继承改写成组合意味着要做更细粒度的类的拆分,要定义更多的类和接口。类和接口的增多也就或多或少地增加代码的复杂程度和维护成本。所以,在实际的项目开发中,我们还是要根据具体的情况,来具体选择该用继承还是组合。

以上就是c# 如何用组合替代继承的详细内容,更多关于c# 组合替代继承的资料请关注服务器之家其它相关文章!

原文链接:https://www.cnblogs.com/gl1573/p/13129284.html

延伸 · 阅读

精彩推荐
  • C#C#正则函数用法实例【匹配、替换、提取】

    C#正则函数用法实例【匹配、替换、提取】

    这篇文章主要介绍了C#正则函数用法,结合实例形式分析了C#基于正则的匹配、替换、提取相关操作技巧,需要的朋友可以参考下...

    pan_junbiao11432021-12-20
  • C#unity实现鼠标拖住3D物体

    unity实现鼠标拖住3D物体

    这篇文章主要为大家详细介绍了unity实现鼠标拖住3D物体,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    人生若只如初见~~~8972022-07-29
  • C#C#常见的几种集合 ArrayList,Hashtable,List<T>,Dictionary<K,V> 遍历方法对比

    C#常见的几种集合 ArrayList,Hashtable,List<T>,Dictionary<K,V>

    本文对C#常见的几种集合 ArrayList,Hashtable,List<T>,Dictionary<K,V> 遍历方法做了简单的对比和介绍,有需要的朋友可以参考一下。...

    天尽头的那片海10762021-11-17
  • C#Unity实现图形相交检测

    Unity实现图形相交检测

    这篇文章主要为大家详细介绍了Unity实现图形相交检测,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    小混沌11652022-09-05
  • C#C#多线程编程之使用ReaderWriterLock类实现多用户读与单用户写同步的方法

    C#多线程编程之使用ReaderWriterLock类实现多用户读与单用户写同步

    这篇文章主要介绍了C#多线程编程之使用ReaderWriterLock类实现多用户读与单用户写同步的方法,涉及C#多线程操作读写锁定的相关技巧,具有一定参考借鉴价值...

    mile9962021-11-03
  • C#C#邮件定时群发工具Atilia用法实例

    C#邮件定时群发工具Atilia用法实例

    这篇文章主要介绍了C#邮件定时群发工具Atilia用法,较为详细的分析了Atilia实现邮件定时群发功能的原理与实现技巧,具有一定参考借鉴价值,需要的朋友可以...

    北风其凉4282021-10-19
  • C#C#在DataTable中根据条件删除某一行的实现方法

    C#在DataTable中根据条件删除某一行的实现方法

    我们通常的方法是把数据源放在DataTable里面,但是偶尔也会需要把不要的行移除,怎么实现呢,下面通过代码给大家介绍c# atatable 删除行的方法,需要的朋...

    网站自由开发者4902021-11-22
  • C#C#中RSA加密与解密的实例详解

    C#中RSA加密与解密的实例详解

    这篇文章主要介绍了C#中RSA加密与解密的实例代码,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下...

    在代码的世界里游走6582022-08-03