【问题标题】:Why we need Abstract Class while we are having Class?为什么我们在有类的时候需要抽象类?
【发布时间】:2012-05-11 16:52:07
【问题描述】:

当我们谈论概念级别的面向对象编程概念时, 假设我们要创建汽车对象。因此我们需要设计父类。假设如果你要做那部分,你会怎么做?

你会使用类还是接口还是抽象类? 那你为什么要使用界面? 为什么我们不能对类/抽象类做同样的事情? 使用接口作为父级有什么好处?

【问题讨论】:

标签: oop class interface conceptual


【解决方案1】:

当您不想实例化超类,但又想实现一些功能时,您需要抽象类。

当你有单父继承并且你不能使用抽象类时需要接口。如果 Java 中有多重继承,我假设您根据您使用的术语在谈论,那么接口将是多余的。

【讨论】:

    【解决方案2】:

    好吧,使用您的 Car 对象,我将尝试通过一个真实世界的示例来解释这个概念。

    想象一下,您是一家制造汽车零件的小公司 (A),您为一家大公司 (B) 制造汽车零件,而这些公司是您的客户,这些零件将被其他汽车制造商使用。

    B 公司必须确保您的产品符合标准,并且与所有汽车制造商兼容。

    这是你的界面。

    接口用于定义一些标准化的方法或属性,以我们为例,我们可以定义一个零件在每个角落有4个孔,用于固定在另一家公司制造的另一个零件上。

    抽象有点不同,抽象比接口更具体(我同意这是一种废话),但它们是具体的,因为它们直接实现(例如接口)一个功能,而抽象类可以永远被实例化。

    抽象类主要用于定义一些基本或共享的功能以使其 DRY。

    因此,您可以创建一个扩展抽象类并实现接口的类。

    这是一个例子:

    interface Vehicle {
       protected $engine;
       protected $wheels;
    
       public function startUp();
       public function stop();
    }
    

    您的 Vehicle 接口定义了需要有引擎和车轮(任意数量)的 Vehicle。

    abstract class Car implements Vehicle {
       protected $wheels = 4;
    
       public function startUp() {
           $this->engine->startUp();
       }
    
       public function stop() {
           $this->engine->stop();
       }
    }
    

    因为startUp()stop() 只是Engine 对象的代理,我们可以将它们放在抽象类中,以便在所有扩展类中重用。 我们将 Car 类设置为有 4 个轮子。

    class Renault extends Car {
       protected $color = 'yellow';
    }
    

    这里我们只需要扩展 Car 抽象类,我们添加一些颜色,因为它很酷。

    现在,假设我们要将雷诺带到洗车站,因为我们正在实现一个已知接口,洗车站将能够在不知道我们的车辆是雷诺的情况下工作,但只是知道它是一辆车。

    这是一个非常基本的示例,它可以设计得更好,但它应该向您展示它是如何工作的。

    不需要接口,至少 PHP 不需要任何类来实现任何接口,但是,你应该使用它们,这通常是一个很好的做法,它在编写 API 时会帮助你,单元测试或在其他开发人员之间共享一些代码。

    【讨论】:

      【解决方案3】:

      冒着过于深入和可能过于戏剧化的风险,我会尽力回答你的问题。

      在您提供的示例的上下文中,带有抽象“Vehicle”类的“Car”类将是最合适的解决方案。这是因为如果您允许,汽车可以成为一个非常复杂的物体。您可能希望编写一个车辆类来抽象出一些任意的更高级别的数据,而不是将所有内容打包到汽车类中。如果您计划稍后实现更多功能或创建其他类型的车辆,例如:飞机,这将非常方便。一个抽象类让你的应用程序更加灵活;如果您觉得需要,您还可以抽象车辆类。从概念上讲,OOP 是关于在抽象和分类方面将代码与我们所有人的思维方式联系起来。但是,如果您要实现简单的功能集,那么简单的类就足够了。

      界面是完全不同的野兽。接口(就计算而言)是一种概念工具,允许程序员在实现和应用程序之间创建一个分离层。例如,如果你想创建一些程序来与声卡通信,你应该创建一个接口类。事实上,这本质上就是设备驱动程序。一些语言,如 Java,有一个内置的接口结构来表示相同的概念。但是,理论上您可以使用任何语言创建界面。

      您可以使用简单的类来实现简单的功能。请记住:类用于对象的实例化;抽象(或基)类用于从类中抽象出数据以创建基本功能。在这两种情况下,它们都处理与应用程序实现不直接相关的代码。但是,这些概念工具不能互换使用。这就是软件工程师和程序员的区别;分别知道何时使用正确的工具和知道如何使用它们。

      如前所述,应使用接口将实现与应用程序分开。如果您与设备驱动程序通信,您不想混入 GUI 代码。接口就像两者之间的联络人。从技术上讲,接口是“实现”的,而不是继承自;然而,在没有明确接口结构的语言中,一个类被用来模拟这个概念,因此会被继承。

      【讨论】:

        【解决方案4】:
        • 抽象类。

        当您有一些概括其他实体但没有“现实世界”化身的概念时,抽象类很有用。

        假设您的程序中有Car 类,并且您将拥有从Car 派生的HummerH2ToyotaCamryDaewooMatiz 类。 CarSome-Abstract-Car,任何汽车都属于 Car 类,但 Car 类本身并不表示任何真正的汽车。

        所以你可以定义Car类如下:

        abstract class Car
        {
            public abstract void Move();
            public abstract void Stop();
            public abstract int GetMaximumSpeed();
            public int GetVehicleID()
            {
                return vehicleID;
            }
        
        
            protected int vehicleID;
        }
        

        然后从Car 派生出HummerH2ToyotaCamryDaewooMatiz,并在那里实现Move()Stop()GetMaximumSpeed()。请注意,Car 类将强制其子类具有 vehicleID 字段。

        • 接口

        接口类似于抽象类,只是不能在接口中声明字段。接口用于声明类必须实现的一些公共功能

        在我们的例子中,我们可以声明接口 IMovable:

        interface IMovable
        {
            void Move();
            void Stop();
            abstract int GetMaximumSpeed();
        }
        

        然后从 IMovable 继承 Car 类:

        abstract class Car: IMovable
        {
            public int GetVehicleID()
            {
                return vehicleID;
            }
            protected int vehicleID;
        }
        

        请注意,现在Car 的子类必须实现Move()Stop() 方法。

        我们可以定义一些Ship 类来实现IMovable 接口。在这种情况下,ShipCar 都可以作为IMovable 对象移动,而不管它是汽车还是轮船或任何实现IMovable 接口的对象。

        P.S.:当然,当您编写一些只有一种类型汽车的简单游戏时,您可以定义非抽象类Car 并使用它。

        【讨论】:

          【解决方案5】:

          我有一个简单的解释,假设你有一个扩展 A 的 B 类。 现在你想在 B 类中进行克隆或者你想进行排序。那么现在你会做什么? 如果你已经创建了一个 Clonable 类/Comparable 类,你如何在 B 中使用它,因为 B 已经扩展了 A。所以你的解决方案是创建另一个扩展可克隆类的 D 类。创建另一个扩展 D 的类 E(以使用克隆方法) 然后.. 意味着因为 java 不支持多重继承,所以你必须不使用任何类来做 dis.. 但是当你将 Clonable 定义为一个接口时,你不需要做的只是在 Ur B 类中实现它。即不需要额外的编码。 这是我为什么要制作接口的解释。 如果我在某处错了,请纠正我。 谢谢。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-12-20
            • 1970-01-01
            • 1970-01-01
            • 2013-02-08
            • 1970-01-01
            • 1970-01-01
            • 2020-04-03
            • 2015-06-05
            相关资源
            最近更新 更多