【问题标题】:PHP/OOP design issue, what is best practice?PHP/OOP 设计问题,最佳实践是什么?
【发布时间】:2015-03-27 19:09:35
【问题描述】:

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

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

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

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

目标:我正在寻找一种仅使用一个类来实现这一点的方法,VehicleCollection 返回一个包含汽车、SUV 等的列表。

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

【问题讨论】:

  • 您不创建专门的集合类,而只使用基础车辆类创建一个。其他一切都是 getter 和 setter 的问题。其他语言为这些东西提供模板类或类模板,php 没有这样的东西。但话又说回来,在你想使用 php 的情况下你不需要它。
  • 您可以保存包含不同类型实例的数组,每个实例都继承自Vehicle
  • 我认为在这里你必须使用依赖注入 - 设计模式。也许它会解决你的问题。
  • 集合对象负责什么?它有什么作用?

标签: php oop


【解决方案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可以加入你的收藏。

有人指出我可能误解了您的问题。如果您只是想过滤一个数组,这将成为一个更简单的问题。如果是这样的话,我什至不会费心去实现一个特殊的类——只需将一个闭包传递给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');

【讨论】:

  • 这里真正的问题是 OP 想要检索一组有限的项目,例如 $collection-&gt;getPlains()
  • 嗯,我在第一次阅读时没有看到,但我可以理解这种解释。对我来说,为什么他将单独的类定义为“集合”并没有真正意义,因为这是一个最佳实践问题,我认为像我建议的那样管理他的数据类型可能是最好的方法。我将更新以提供过滤方法
  • 我个人会将集合更改为多维数组,其中键是添加​​的对象的类型,有点像其他答案,但动态。这将提高 imo 的性能,因为您可以根据类型返回集合,而不是需要 foreach 每个元素并正确映射它
【解决方案2】:

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

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

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

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

我还没有完全考虑到这一点,它可能需要一些调整。但是,如果它完全关闭,请跟我打招呼。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    • 2011-04-08
    相关资源
    最近更新 更多