使用抽象类和接口进行多态

In this article, you'll learn how to share and enforce code with polymorphism using abstract classes and interfaces.

在本文中,您将学习如何使用抽象类和接口来共享和执行具有多态性的代码。

We will dive deeper into Object Oriented Programming and try to think in terms of Design Patterns to share and enforce our code using Polymorphism.

我们将更深入地研究面向对象的编程,并尝试从设计模式的角度来考虑使用多态来共享和执行我们的代码。

抽象类 (Abstract Class)

Let’s say we have a class called Man with some properties (name, age, height, fav_drinks and fav_sports) and methods (giveFirmHandshakes, beStubborn and notPutToiletPaper).

假设我们有一个名为Man的类,它具有一些属性( nameageheightfav_drinksfav_sports )和方法( giveFirmHandshakesbeStubbornnotPutToiletPaper )。

<?php
 
class Man
{
    public $name;
    public $age;
    public $height;
    public $fav_sports;
    public $fav_drinks;
    
    public function __construct($name, $age, $height)
    {
        $this->name = $name;
        $this->age = $age;
        $this->height = $height;
    }
    
    public function giveFirmHandshakes()
    {
        return "I give firm handshakes.";
    }
 
    public function beStubborn()
    {
        return "I am stubborn.";
    }
 
    public function notPutToiletPaper()
    {
        return "It's not humanly possible to remember to put toilet paper rolls when they are finished";
    }
}

We need to specify name, age and height to instantiate this class as required by the constructor.

我们需要指定名称,年龄和高度,以根据构造函数的要求实例化此类。

<?php
$jack = new Man('Jack', '26', '5 Feet 6 Inches');

echo sprintf('%s - %s - %s', $jack->name, $jack->age, $jack->height);
// => Jack - 26 - 5 Feet 6 Inches

Now, let’s say we want to add a new method to this class called isActive.

现在,假设我们要向此类添加一个名为isActive的新方法。

This method checks whether the property active and returns the appropriate message depending on the value of active, with default value of false. We can set it to true for those men that are active.

此方法检查属性是否为active,并根据active的值(默认值为false)返回适当的消息。 对于活跃的男人,我们可以将其设置为true。

<?php
 
class Man
{
    public $name;
    public $age;
    public $height;
    public $fav_sports;
    public $fav_drinks;
    public $active = false;
    
    .....
    .....
    
    public function isActive()
    {
        if ($this->active == true) {
            return "I am an active man.";
        } else {
            return "I am an idle man.";
        }
    }
}

$jack = new Man('Jack', '26', '5 Feet 6 Inches');
$jack->active = true;
echo $jack->isActive();
// => I am an active man.

$jake = new Man('Jake', '30', '6 Feet');
echo "\n" . $jake->isActive();
// => I am an idle man.

What if a man is not JUST active or idle?

如果一个人不是仅仅活跃或闲散怎么办?

What if there is a scale of 1 to 4 that measures how active a man is (1 – idle, 2 – lightly active, 3- moderately active, 4- very active)?

如果以1到4的比例来衡量一个人的运动能力(1 –闲置,2 –轻度运动,3-中度运动,4-非常运动)怎么办?

We can have an if..elseif..else statement like this:

我们可以有一个if..elseif..else语句,如下所示:

<?php

public function isActive()
{
    if ($this->active == 1) {
        return "I am an idle man.";
    } elseif ($this->active == 2) {
        return "I am a lightly active man.";
    } elseif ($this->active == 3) {
        return "I am a moderately active man.";
    } else {
        return "I am a very active man.";
    }
}

Now, let’s take this a step further.

现在,让我们更进一步。

What if Man’s active property is not just an integer (1, 2, 3, 4, etc)? What if the value of active is “athletic” or “lazy”?

如果Man的活动属性不只是整数(1、2、3、4等)怎么办? 如果active的值为“运动”或“懒惰”怎么办?

Don’t we have to add more elseif statements looking for a match with those strings?

我们是否不必添加更多elseif语句来寻找与这些字符串匹配的内容?

Abstract classes can be used for such a scenario.

抽象类可用于这种情况。

With abstract classes, you basically define the class as abstract and the methods you want to enforce as abstract without actually putting any code inside those methods.

使用抽象类,您基本上将类定义为抽象,而将要实施的方法定义为抽象,而无需在这些方法中实际放置任何代码。

Then you create a child class extending the parent abstract class and implement the abstract methods in that child class.

然后,创建一个扩展父抽象类的子类,并在该子类中实现抽象方法。

This way, you will be enforcing all the child classes to define their own version of abstract methods. Let’s see how we can set our isActive() method as abstract.

这样,您将强制所有子类定义其自己的抽象方法版本。 让我们看看如何将isActive()方法设置为抽象。

1:将类定义为抽象。 (1: Define the class as abstract.)

<?php
abstract class Man
{
.....
.....
}

2:为要在抽象类中强制执行的方法创建一个抽象方法。 (2: Create an abstract method for the method you want to enforce inside the abstract class.)

<?php
abstract class Man
{
.....
.....
abstract public function isActive();
}

3:创建扩展抽象类的子类。 (3: Create a child class extending the abstract class.)

<?php

class AthleticMan extends Man
{
.....
.....
}

4:在子类中实现抽象方法。 (4: Implement the abstract method inside the child class.)

<?php
class AthleticMan extends Man
{
    public function isActive()
    {
        return "I am a very active athlete.";
    }
}

5:实例化子类(不是抽象类)。 (5: Instantiate the child class (NOT the abstract class).)

<?php
$jack = new AthleticMan('Jack', '26', '5 feet 6 inches');
echo $jack->isActive();
// => I am a very active athlete.

Complete abstract class definition and implementation code:

完整的抽象类定义和实现代码:

<?php
 
abstract class Man
{
    public $name;
    public $age;
    public $height;
    public $fav_sports;
    public $fav_drinks;
    
    public function __construct($name, $age, $height)
    {
        $this->name = $name;
        $this->age = $age;
        $this->height = $height;
    }
    
    public function giveFirmHandshakes()
    {
        return "I give firm handshakes.";
    }
 
    public function beStubborn()
    {
        return "I am stubborn.";
    }
 
    public function notPutToiletPaper()
    {
        return "It's not humanly possible to remember to put toilet paper rolls when they are finished";
    }
    
    abstract public function isActive();
}

class AthleticMan extends Man
{
    public function isActive()
    {
        return "I am a very active athlete.";
    }
}

$jack = new AthleticMan('Jack', '26', '5 feet 6 inches');
echo $jack->isActive();
// => I am a very active athlete.

In this code, you will notice that isActive() abstract method is defined inside Man abstract class and it is implemented inside child class AthleticMan.

在此代码中,您将注意到isActive()抽象方法是在Man抽象类中定义的,并且是在子类AthleticMan

Now Man class cannot be instantiated directly to create an object.

现在,不能直接实例化Man类来创建对象。

<?php
$ted = new Man('Ted', '30', '6 feet');
echo $ted->isActive();
// => Fatal error:  Uncaught Error: Cannot instantiate abstract class Man

Also, every child class of the abstract class (Man class) needs to implement all the abstract methods. Lack of such implementation will result in a fatal error.

同样,抽象类( Man类)的每个子类都需要实现所有抽象方法。 缺乏这种实现将导致致命错误。

<?php
class LazyMan extends Man
{
    
}

$robert = new LazyMan('Robert', '40', '5 feet 10 inches');
echo $robert->isActive();
// => Fatal error:  Class LazyMan contains 1 abstract method 
// => and must therefore be declared abstract or implement 
// => the remaining methods (Man::isActive)

By using abstract classes, you can enforce certain methods to be implemented individually by the child classes.

通过使用抽象类,您可以强制某些方法由子类单独实现。

接口 (Interface)

There is another Object Oriented Programming concept that is closely related to Abstract Classes called Interface.

还有另一个与抽象类紧密相关的面向对象编程概念,称为接口。

The only difference between Abstract Classes and Interfaces is that in Abstract Classes, you can have a mix of defined methods (giveFirmHandshakes(), isStubborn(), etc.) and abstract methods (isActive()) inside the parent class. But in Interfaces, you can only define (not implement) methods inside the parent class.

抽象类和接口之间的唯一区别是,在抽象类中,可以在父类中混合使用已定义的方法( giveFirmHandshakes()isStubborn()等)和抽象方法( isActive() )。 但是在接口中,您只能在父类内部定义(而不是实现)方法。

Let’s see how we can convert Man abstract class above to an interface.

让我们看看如何将上面的Man抽象类转换为接口。

1:使用所有方法定义接口(使用接口代替类)。 (1: Define the interface with all the methods (use interface instead of class).)

<?php
interface Man
{
    public function __construct($name, $age, $height);
    
    public function giveFirmHandshakes();
 
    public function beStubborn();
 
    public function notPutToiletPaper();
    
    public function isActive();
}

2:创建一个实现接口的类(使用实现而不是扩展)。 (2: Create a class that implements the interface (use implements instead of extends). )

This class must implement ALL the methods defined inside the interface including the constructor method.

此类必须实现接口内部定义的所有方法,包括构造方法。

<?php
class AthleticMan implements Man
{
    public $name;
    public $age;
    public $height;
    
    public function __construct($name, $age, $height)
    {
        $this->name = $name;
        $this->age = $age;
        $this->height = $height;
    }
    
    public function giveFirmHandshakes()
    {
        return "I give firm handshakes.";
    }
    
    public function beStubborn()
    {
        return "I am stubborn.";
    }
 
    public function notPutToiletPaper()
    {
        return "It's not humanly possible to remember to put toilet paper rolls when they are finished";
    }
    
    public function isActive()
    {
        return "I am a very active athlete.";
    }
}

3:实例化实施类(AthleticMan) (3: Instantiate the implementing class (AthleticMan))

<?php
$jack = new AthleticMan('Jack', '26', '5 feet 6 inches');
echo $jack->isActive();
// => I am a very active athlete.

With interfaces, you need to keep in mind that:

使用接口时,请记住:

  • The methods cannot be implemented inside the interface.

    该方法不能在接口内部实现。
  • Variables (properties) cannot be defined inside the interface.

    不能在接口内部定义变量(属性)。
  • All the methods defined inside the interface need to be implemented in the child (implementing) class.

    接口内定义的所有方法都需要在子类(实现)中实现。
  • All the necessary variables need to be defined inside the child class.

    所有必需的变量都需要在子类中定义。
  • Man interface enforces its implementing classes to implement all the methods in the interface.

    Man接口强制实施其实现类,以实现接口中的所有方法。

So, what is the use of interfaces?

那么,接口的用途是什么?

Can’t we just create a new class AthleticMan and create all the methods instead of implementing the interface?

我们不能只创建一个新的AthleticMan类并创建所有方法而不是实现接口吗?

This is where Design Patterns come into play.

这就是设计模式发挥作用的地方。

Interfaces are used when there is a base class (Man) that wants to enforce you to do things (construct an object, giveFirmHandshakes, beStubborn, notPutToiletPaper and check if you are active) but doesn’t want to tell you exactly how to do it.

当有一个基类( Man )想要强制您执行操作(构造对象,giveFirmHandshakes,beStubborn,notPutToiletPaper并检查您是否处于活动状态)但不希望确切告诉您如何执行操作时,使用接口。

You can just go ahead and create implementing classes with implementations as you deem fit.

您可以继续使用自己认为合适的实现创建实现类。

As long as all the methods are implemented, Man interface doesn’t care how.

只要实现了所有方法, Man接口就不会在乎。

We have gone over how and when to use abstract classes and interfaces in PHP. Using these OOP concepts to have classes with different functionality sharing the same base “blueprint” (abstract class or interface) is called Polymorphism.

我们已经讨论了如何以及何时使用PHP中的抽象类和接口。 使用这些OOP概念使具有不同功能的类共享同一基本“蓝图”(抽象类或接口)称为多态。

翻译自: https://www.freecodecamp.org/news/polymorphism-using-abstract-class-and-interface/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值