簡體   English   中英

我們是否可以強制具體的類來實現PHP抽象類中指定的接口?

[英]Can we force concrete classes to implement an interface specified in an abstract class in PHP?

是否可以在抽象類中指定必須由PHP的具體實現來實現的接口?

目前,我們正在做類似以下的事情(希望可以簡單到可以遵循):

<?php

declare(strict_types=1);

interface SensorObserver
{
    public function sensorChanged( array $sensorData );
}

class SensorSubject
{
    protected $observers = [];

    public function addSensorObserver( SensorObserver $sensorObserver ) : bool
    {
        if ( !in_array( $sensorObserver, $this->observers ) )
        {
            $this->observers[] = $sensorObserver;
            return true;
        }
        return false;
    }

    public function removeSensorObserver( SensorObserver $sensorObserver ) : bool
    {
        if ( !in_array( $sensorObserver, $this->observers ) )
        {
            return false;
        }
        else
        {
            unset( $this->observers[array_search( $sensorObserver, $this->observers )]); 
            return true;
        }
    }

    public function notifyObservers( array $sensorData )
    {
        foreach( $this->observers as $observer )
        {
            $observer->sensorChanged( $sensorData );
        }
    }
}

abstract class GenericDisplay
{
    protected $name;
    protected $sensorData;
    protected $displayData;

    abstract public function showDisplay();
    abstract protected function generateDisplayData();

    public function __construct( string $name )
    {
        $this->name = $name;
        $this->sensorData = [];
        $this->displayData = [];
    }
}

class DisplayDeviceA extends GenericDisplay implements SensorObserver
{
    public function __construct()
    {
        parent::__construct( 'DisplayDeviceA' );
        $this->sensorData = [ 'SensorTypeA' => 0.0, 'SensorTypeB' => 0.0 ];
        $this->generateDisplayData();
    }

    public function showDisplay()
    {
        echo PHP_EOL . "{$this->name}: " . PHP_EOL;
        foreach ( $this->displayData as $key => $value )
        {
            echo "{$key}: {$value}" . PHP_EOL;
        }
    }

    protected function generateDisplayData()
    {
        // Complicated processing done for output here :)
        $this->displayData = $this->sensorData;
    }

    public function sensorChanged( array $sensorData )
    {
        $dirtySensorData = false;

        foreach( $sensorData as $key => $value )
        {
            if ( array_key_exists( $key, $this->sensorData ) )
            {
                // This is just an example, <imagine custom processing here  when sensor data changes />,
                // otherwise we could just implement in the base abstract class or perhaps with a trait
                $this->sensorData[$key] = $value;
                $dirtySensorData = true;
            }
        }

        if ( $dirtySensorData )
        {
            $this->generateDisplayData();
        }
    }
}

class DisplayDeviceB extends GenericDisplay implements SensorObserver
{
    public function __construct()
    {
        parent::__construct( 'DisplayDeviceB' );
        $this->sensorData = [ 'SensorTypeA' => 0.0, 'SensorTypeB' => 0.0, 'SensorTypeC' => 0.0 ];
        $this->generateDisplayData();
    }

    public function showDisplay()
    {
        echo PHP_EOL . "{$this->name}: " . PHP_EOL;
        foreach ( $this->displayData as $key => $value )
        {
            echo "{$key} => {$value}" . PHP_EOL;
        }
    }

    protected function generateDisplayData()
    {
        // Complicated processing done for output here :)
        $this->displayData = $this->sensorData;
    }

    public function sensorChanged( array $sensorData )
    {
        $dirtySensorData = false;

        foreach( $sensorData as $key => $value )
        {
            if ( array_key_exists( $key, $this->sensorData ) )
            {
                // Again, just an example...
                $this->sensorData[$key] = $value;
                $dirtySensorData = true;
            }
        }

        if ( $dirtySensorData )
        {
            $this->generateDisplayData();
        }
    }
}

class DisplayDeviceC extends GenericDisplay implements SensorObserver
{
    public function __construct()
    {
        parent::__construct( 'DisplayDeviceC' );
        $this->sensorData = [ 'SensorTypeB' => 0.0, 'SensorTypeD' => 0.0 ];
        $this->generateDisplayData();
    }

    public function showDisplay()
    {
        echo PHP_EOL . "{$this->name}: " . PHP_EOL;
        foreach ( $this->displayData as $key => $value )
        {
            echo "{$key} --> {$value}" . PHP_EOL;
        }
    }

    protected function generateDisplayData()
    {
        // Complicated processing done for output here :)
        $this->displayData = $this->sensorData;
    }

    public function sensorChanged( array $sensorData )
    {
        $dirtySensorData = false;

        foreach( $sensorData as $key => $value )
        {
            if ( array_key_exists( $key, $this->sensorData ) )
            {
                // Again, just an example...
                $this->sensorData[$key] = $value;
                $dirtySensorData = true;
            }
        }

        if ( $dirtySensorData )
        {
            $this->generateDisplayData();
        }
    }
}

$testDisplays = [ new DisplayDeviceA(), new DisplayDeviceB(), new DisplayDeviceC() ];
foreach( $testDisplays as $display )
{
    $display->showDisplay();
}

$sensorSubject = new SensorSubject();
foreach( $testDisplays as $display )
{
    $sensorSubject->addSensorObserver( $display );
}

$sensorSubject->notifyObservers( ['SensorTypeB' => 10.0, 'SensorTypeD' => 5.0] );

foreach( $testDisplays as $display )
{
    $display->showDisplay();
}

想知道是否有某種寫方法:

interface SensorObserver
{
    public function sensorChanged( array $sensorData );
}

abstract class GenericDisplay implements SensorObserver
{
    ...
    abstract public function sensorChanged( array $sensorData );
    ...
}

class ConcreteDisplay extends GenericDisplay
{
    public function sensorChanged( array $sensorData ) { ... };
}

感謝下面的@Mark Ba​​ker和@Pael Petrov。 如果有人偶然發現此問題,請使用以下示例:

<?php

interface AnInterface
{
    public function foo();
}

abstract class AbstractClass implements AnInterface
{
    //...
}

class ConcreteClass extends AbstractClass
{
    public function foo()
    {
        echo 'foo';
    }
}


$concrete = new ConcreteClass();
$concrete->foo();

如果抽象類實現了某些接口,則具體類會自動實現抽象類的所有接口,因此您只需要擴展抽象類即可:

class ConcreteDisplay extends GenericDisplay
{
    //implement interface methods here 
    //if not implemented in the parend class
}

這樣就可以了

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM