PHP / OOP设计问题,什么是最佳实践?

时间:2015-03-27 19:09:35

标签: php oop

我使用的是PHP 5.3。我有一个车辆类。这些类继承自Vehicle:Car,SUV,Lorry。

我需要获取一个包含从Vehicle继承的特定类型对象的数组。它可以是一系列汽车,SUV等......

我解决它的方法是我用静态方法创建了一个名为CarCollection的类,它返回汽车列表。然后是一个名为SUV的SUVCollection类......

但如果我要添加一个新的车辆类(让我们称之为Airplane),那么我需要创建一个新的AirPlaneCollection类。这是一个糟糕的选择吗?

目标:我正在寻找一种仅使用一个类来实现此目的的方法,VehicleCollection返回一个Cars,SUV等列表。

我怎么能在代码中知道在这个特定的脚本中,VehicleCollection :: getVehicles()会返回汽车而不是SUV?也许我可以从调用它的位置检查类的逻辑,或者我将调用者对象作为参数发送,然后检查它是哪个类并根据它获取VehicleCollection :: getVehicles()以返回forle SUV而不是车。

2 个答案:

答案 0 :(得分:1)

您可以尝试制作自己的收藏类型,该类型可以验证所有内容都是车辆,但也可以强制执行所有相同类型的车辆。

<?php
class Vehicle {}

class Car extends Vehicle {}

class SUV extends Vehicle {}

// This doesn't need to be an SplDoublyLinkedList, it's just
// a convenient datastructure to demo with
class VehicleCollection extends SplDoublyLinkedList
{
    public function add($index, Vehicle $obj)
    {
        $this->validateType($obj);
        parent::add($index, $obj);
    }

    public function push(Vehicle $obj)
    {
        $this->validateType($obj);
        parent::push($obj);
    }

    protected function validateType($obj)
    {
        // If we have anything in here, ensure next is the same vehicle type
        if (!($this->isEmpty() || $this->top() instanceof $obj)) {
            throw new InvalidArgumentException('Argument passed to ' . __CLASS__ . '::' . __FUNCTION__ . ' must all be instances of same type.');
        }
    }
}

// Make a new collection
$col = new VehicleCollection();

// Let's have a couple cars
$car = new Car;
$car2 = new Car;

// And an SUV
$suv = new SUV;

// Let's add our cars
$col->push($car);
$col->push($car2);

var_dump($col);
/* Collection right now:
class VehicleCollection#1 (2) {
  private $flags =>
  int(0)
  private $dllist =>
  array(2) {
    [0] =>
    class Car#2 (0) {
    }
    [1] =>
    class Car#3 (0) {
    }
  }
}
*/

// Now we try to add an SUV
$col->push($suv);

// and get this:
// PHP Fatal error:  Uncaught exception 'InvalidArgumentException' with message 'Argument passed to VehicleCollection::validateType must all be instances of same type.'

这有额外的好处,如果你进一步扩展,例如制作了class SportsCar extends Car {},即SportsCar 可以进入您的收藏。

有人指出我可能误解了你的问题。如果您只是尝试过滤数组,这将成为一个更简单的问题。如果是这样的话,我甚至不愿意实现一个特殊的类 - 只需将一个Closure传递给array_filter,这是一个非常易读且易于在其他地方使用的模式:

$vehicles = [$car, $suv, $car2];
$cars = array_filter($vehicles, function($vehicle) { return $vehicle instanceof Car; });
$suvs = array_filter($vehicles, function($vehicle) { return $vehicle instanceof SUV; });

因此在该示例中,车辆阵列具有SUV,并且一旦过滤,$ cars阵列仅具有汽车。如果你想把它作为一个类方法,你可以做以下几点:

public function getAllOfType($type)
{
    return array_filter(
        $this->vehicles,
        function($vehicle) { return is_a($vehicle, $type); }
    );
}

然后只从您的收藏中抓取汽车:

$cars = $myVehicleCollection->getAllOfType('Car');

答案 1 :(得分:0)

父类中的静态属性如何看起来像:

array( 'cars' => array(car instances),
   'suvs' =>array(suv instances).
    ....
)

然后你必须在你的构造函数和析构函数中添加逻辑来添加和删除这个数组中的对象。

然后,您可以致电Vehicle::thatArry['cars']获取所有汽车的列表。但是当然你想在那个数组周围抛出一些不错的getter和setter。

我还没有完全想到这一点,可能需要一些调整。但是,如果它完全关闭,霍拉对我。