当前位置:  开发笔记 > 编程语言 > 正文

是否应该从编程语言中删除(非接口类型的)继承?

如何解决《是否应该从编程语言中删除(非接口类型的)继承?》经验,为你挑选了6个好方法。

这是一个颇具争议的话题,在你说"不"之前,真的,真的需要吗?

我已经编程了大约10年,而且我不能诚实地说,我可以回想起继承解决了一个无法用另一种方式解决的问题.另一方面,当我使用继承时,我可以回想起很多次,因为我觉得我必须这样做,或者因为我虽然我很聪明并最终付出了代价.

我无法真正看到任何情况,从实现的角度来看,无法使用聚合或其他技术而不是继承.

我唯一需要注意的是,我们仍然允许继承接口.

(更新)

让我们举例说明为什么需要它而不是说"有时它只是需要它".这根本没有用.你的证明在哪里?

(更新2代码示例)

这是经典的形状示例,更强大,更明确的IMO,没有继承.现实世界中的情况几乎从来都不是真的"是一种"的东西.几乎总是"以实施方式"更准确.

public interface IShape
{
    void Draw();
}

public class BasicShape : IShape
{
    public void Draw()
    {
        // All shapes in this system have a dot in the middle except squares.
        DrawDotInMiddle();
    }
}

public class Circle : IShape
{
    private BasicShape _basicShape;

    public void Draw()
    {
        // Draw the circle part
        DrawCircle();
        _basicShape.Draw();
    }
}

public class Square : IShape
{
    private BasicShape _basicShape;

    public void Draw()
    {
        // Draw the circle part
        DrawSquare();
    }
}

Jon Skeet.. 20

我刚才在博客上写道这是一个古怪的想法.

我不认为它应该被删除,但我认为类应该默认密封,以阻止继承,当它不合适时.它是一个功能强大的工具,但它就像一个链锯 - 除非它是完美的工具,否则你真的不想使用它.否则你可能会开始失去四肢.

这是潜在的语言功能,例如混合,这将使其更容易生活,IMO.



1> Jon Skeet..:

我刚才在博客上写道这是一个古怪的想法.

我不认为它应该被删除,但我认为类应该默认密封,以阻止继承,当它不合适时.它是一个功能强大的工具,但它就像一个链锯 - 除非它是完美的工具,否则你真的不想使用它.否则你可能会开始失去四肢.

这是潜在的语言功能,例如混合,这将使其更容易生活,IMO.



2> Greg Beech..:

在基类具有多个对每个派生类具有相同实现的方法的情况下,继承可能非常有用,以保存每个派生类不必实现样板代码.以.NET Stream类为例,它定义了以下方法:

public virtual int Read(byte[] buffer, int index, int count)
{
}

public int ReadByte()
{
    // note: this is only an approximation to the real implementation
    var buffer = new byte[1];
    if (this.Read(buffer, 0, 1) == 1)
    {
        return buffer[0];
    }

    return -1;
}

因为继承是可用的,所以基类可以ReadByte为所有实现实现该方法,而无需担心它.在类上有许多其他类似于默认或固定实现的方法.所以在这种情况下,与一个界面相比,它是一个非常有价值的东西,你可以选择让每个人重新实现所有东西,或创建一个StreamUtil他们可以调用的类型类(yuk!).

为了澄清,继承所有我需要写的创建DerivedStream类是这样的:

public class DerivedStream : Stream
{
    public override int Read(byte[] buffer, int index, int count)
    {
        // my read implementation
    }
}

然而,如果我们使用接口和方法的默认实现,StreamUtil我必须编写更多代码:

public class DerivedStream : IStream
{
    public int Read(byte[] buffer, int index, int count)
    {
        // my read implementation
    }

    public int ReadByte()
    {
        return StreamUtil.ReadByte(this);
    }
}

}

所以这不是一个更多的代码,而是在类上增加了几个方法,它只是编译器可以处理的不必要的样板.为什么要使实施比必要的更痛苦?我不认为继承是最重要的,但是如果正确使用它会非常有用.


您可以对迭代器(yield return)说同样的事情 - 手动编写状态机可以更清楚地了解迭代的工作原理,因为除非您反汇编程序集,否则您甚至看不到生成的代码,但是您真的想要全部编写锅炉板代码?

3> Norman Ramse..:

当然,你可以在没有对象和继承的情况下愉快地编写出色的程序; 功能程序员一直这样做.但是,让我们不要仓促.任何对此主题感兴趣的人都应该查看Xavier Leroy邀请的关于Objective Caml中的类和模块的演讲的幻灯片.Xavier做了一个很好的工作,在不同类型的软件演化的背景下,确定了继承做得好并且做得不好.

所有语言都是图灵完备的,因此当然不需要继承.但作为继承价值的论证,我提出了Smalltalk蓝皮书,尤其是Collection层次结构Number层次结构.令我印象深刻的是,熟练的专家可以在不影响现有系统的情况下添加全新的数字(或集合).

我还会提醒提问者"继承人的杀手级应用程序":GUI工具包.一个设计良好的工具包(如果你能找到)可以非常,非常容易地添加新的图形交互小部件.

说了这么多,我认为继承具有天生的弱点(你的程序逻辑被涂抹在一大堆类上),它应该很少使用,只能由熟练的专业人员使用.一个拥有计算机科学学士学位的人对继承知之甚少 - 应该允许这些人继承其他需要的课程,但绝不应该编写其他程序员继承的代码.这项工作应该留给那些真正知道自己在做什么的大师级程序员.他们应该不情愿地做到这一点!

对于使用完全不同的机制解决类似问题的有趣尝试,人们可能想要查看Haskell类型类.


阅读自我(http://research.sun.com/self/papers/self-power.html),看看你是否仍然这么认为.

4> Clint Miller..:

我希望语言能提供一些机制,使其更容易委托给成员变量.例如,假设接口I有10个方法,C1类实现此接口.假设我想要实现类似C1的类C2,但是方法m1()被覆盖.在不使用继承的情况下,我会按照以下方式执行此操作(在Java中):

public class C2 implements I {
    private I c1;

    public C2() {
       c1 = new C1();
    }

    public void m1() {
        // This is the method C2 is overriding.
    }

    public void m2() {
        c1.m2();
    }

    public void m3() {
        c1.m3();
    }

    ...

    public void m10() {
        c1.m10();
    }
}

换句话说,我必须明确地编写代码来将方法m2..m10的行为委托给成员变量m1.这有点痛苦.它也使代码混乱,因此很难在C2类中看到真正的逻辑.这也意味着无论何时向接口I添加新方法,我都必须向C1明确添加更多代码,以便将这些新方法委托给C1.

我希望语言允许我说:C1实现了我,但如果C1缺少某些方法,我会自动委托给成员变量c1.这会将C1的大小减少到恰好

public class C2 implements I(delegate to c1) {
    private I c1;

    public C2() {
       c1 = new C1();
    }

    public void m1() {
        // This is the method C2 is overriding.
    }
}

如果语言允许我们这样做,那么避免使用继承会容易得多.

这是我写的关于自动委派的博客文章.



5> angry person..:

继承是可以使用的工具之一,当然可以被滥用,但我认为语言必须有更多的更改才能删除基于类的继承.

让我们抓住我的世界,主要是C#开发.

为了让微软取消基于类的继承,他们必须为处理接口提供更强大的支持.像聚合这样的东西,我需要添加大量的样板代码,只是为了将接口连接到内部对象.无论如何,这确实应该完成,但在这种情况下是必需的.

换句话说,以下代码:

public interface IPerson { ... }
public interface IEmployee : IPerson { ... }
public class Employee : IEmployee
{
    private Person _Person;
    ...

    public String FirstName
    {
        get { return _Person.FirstName; }
        set { _Person.FirstName = value; }
    }
}

这基本上要短得多,否则我会有很多这些属性只是为了让我的课程模仿一个人足够好,这样的事情:

public class Employee : IEmployee
{
    private Person _Person implements IPerson;
    ...
}

这可以自动创建必要的代码,而不是我必须编写它.如果我将对象转换为IPerson,只返回内部引用就没有用了.

因此,在基于类的继承可以从表中取消之前,必须更好地支持这些事情.

此外,您将删除可见性等内容.一个界面真的只有两个可见性设置:那里,而不是那里.在某些情况下,您或者我认为,您将被迫公开更多内部数据,以便其他人可以更轻松地使用您的课程.

对于基于类的继承,您通常可以公开一些后代可以使用的访问点,但外部代码不能,并且您通常只需要删除这些访问点,或者让它们对所有人开放.不确定我是否喜欢其他选择.

我最大的问题是具体删除这些功能的重点是什么,即使计划是作为一个例子,构建D#,一种新的语言,如C#,但没有基于类的继承.换句话说,即使你计划建立一种全新的语言,我仍然不完全确定最终目标是什么.

目标是删除可能被滥用的东西,如果不是在正确的手中?如果是这样,我有一个一英里长的列表,用于各种编程语言,我真的希望首先看到地址.

在该列表的顶部:Delphi中的with关键字.这个关键词不仅仅是用脚射击自己,就像编译器购买霰弹枪一样,来到你家并瞄准你.

我个人喜欢基于类的继承.当然,你可以把自己写进一个角落.但我们都可以这样做.删除基于类的继承,我只会找到一种用脚射击自己的新方法.

我现在把那把霰弹枪放在哪里......



6> 小智..:

在所有类上实现ISystemObject非常有趣,这样您就可以访问ToString()和GetHashcode().

另外,ISystemWebUIPage接口祝你好运.

如果你不喜欢继承,我的建议是一起停止使用.NET.有太多的场景可以节省时间(参见DRY:不要重复自己).

如果使用继承会破坏您的代码,那么您需要退后一步并重新考虑您的设计.

我更喜欢接口,但它们不是银弹.

推荐阅读
手机用户2402851335
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有