4 回答
TA贡献1802条经验 获得超10个赞
考虑一下:
class NotBicycle implements Vehicle { ... }
interface VehicleInterface {
public function create(Vehicle $vehicle);
}
class BicycleService implements VehicleInterface {
public function create(Bicycle $bicycle) {
$bicycle->setManufacturer('Some company'); // Common for all Vehicle objects
$bicycle->addSaddle(); // Common only for Bicycle objects
}
}
function createVehicle(VehicleInterface $service, Vehicle $vehicle) {
$service->create($vehicle);
}
$service = new BicycleService();
$vehicle = new NotBicycle();
createVehicle($service, $vehicle);
即使你以某种方式只能接受Bicycle其中的一个BicycleService,createVehicle($service, $vehicle)仍然会起作用,因为VehicleInterface有一个方法create(Vehicle $vehicle)。因此,为了让它按照您想要的方式工作,您需要从根本上打破界面的本质。
您唯一真正的选择是添加运行时类型检查。就像例如
class BicycleService implements VehicleInterface {
public function create(Vehicle $bicycle) {
if (!$bicycle instance of Bicycle) {
throw new TypeError('Expected Bicycle but got '.get_class($bicycle));
}
$bicycle->setManufacturer('Some company'); // Common for all Vehicle objects
$bicycle->addSaddle(); // Common only for Bicycle objects
}
}
您尝试做的事情称为协变方法参数类型,在大多数面向对象的编程语言中是不允许的,因为它违反了里氏替换原则
TA贡献1828条经验 获得超6个赞
Bicycle
您需要删除带有 的类型Vehicle
。你可能需要检查if ($bicycle instanceof Bicycle)
抽象层次太抽象了。
TA贡献1864条经验 获得超6个赞
您需要将您的Vehicle类传递给它,然后用于instanceof检查接口。在下面的例子中,我更改了命名约定。
interface Vehicle {
public function setSpeedLimit(Float $limit) : Car;
public function setManufacturer(String $manufacturer) : MethodOfTransport;
}
interface NonVehicle {
public function addSaddle() : Bicycle;
public function setManufacturer(String $manufacturer) : MethodOfTransport;
}
abstract class MethodOfTransport
{
public function setManufacturer(String $manufacturer) : MethodOfTransport { return $this; }
}
class Bicycle extends MethodOfTransport implements NonVehicle
{
}
class Car extends MethodOfTransport implements Vehicle
{
public function setSpeedLimit(Float $limit) : Car { return $this; }
}
$b = new Bicycle();
$c = new Car();
如前所述,我消除了命名约定的一些混乱,因为 aBicycle不是 aVehicle而是 a MethodOfTransport。
interface VehicleServiceInterface
{
# Change the return DataType to MethodOfTransport if Vehicle implements multiple classes
public function create(MethodOfTransport $t) : Car;
}
class VehicleService implements VehicleServiceInterface
{
public function create(MethodOfTransport $t) : Car
{
if (!$t instanceof Vehicle)
throw new Exception( 'Cannot create a Vehicle on a NonVehicle instance.' );
$t->setManufacturer( 'Foo' )->setSpeedLimit( 140 );
return $t;
}
}
$c = (new VehicleService())->create( $c ); // Works
$b = (new VehicleService())->create( $b ); // Throws Exception
和Car都是Bicyclea MethodOfTransport,但是,一个是 a Vehicle,另一个是 a NonVehicle。两者都可以传递到方法中,但我们可以使用 来确保它是正确的类型instanceof。
但是,您可以将返回类型设置为方法的返回类型,create因为Car我们Vehicle在本例中仅过滤实例。如果您有多个Vehicle已实现的类,请将其更改为返回MethodOfTransport
- 4 回答
- 0 关注
- 127 浏览
添加回答
举报