我们可以强制具体类来实现PHP中抽象类中指定的接口吗?

时间:2016-02-17 09:15:23

标签: php oop

是否可以在抽象类中指定必须由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();

1 个答案:

答案 0 :(得分:1)

如果抽象类实现了一些接口具体类,则会自动实现抽象类的所有接口,因此您只需要扩展抽象类:

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

这将完成工作