[英]PHP/OOP design issue, what is best practice?
I'm using PHP 5.3. 我正在使用PHP 5.3。 I have a Vehicle class.
我有车辆课。 These classes have inherited from Vehicle: Car, SUV, Lorry.
这些类继承自Vehicle:Car,SUV,Lorry。
I need to get an array holding a specific type of objects inherited from Vehicle. 我需要获取一个数组,其中包含从Vehicle继承的特定类型的对象。 It can be an array of Cars, SUVs, etc...
它可以是一系列汽车,SUV等。
The way I solved it was that I created a class named CarCollection with a static method, which returns the list of cars. 解决问题的方法是用静态方法创建了一个名为CarCollection的类,该类返回汽车列表。 Then a class named SUVCollection for SUV...
然后是一个名为SUVCollection的SUV类...
But if I were to add a new vehicle class (let's call it Airplane), then I would need to create a new AirPlaneCollection class. 但是,如果我要添加一个新的飞行器类(我们称之为Airplane),那么我将需要创建一个新的AirPlaneCollection类。 Is this a bad choice?
这是一个不好的选择吗?
The goal: I'm looking for a way to implement this using only one class, VehicleCollection returns a list of Cars, SUV etc. 目标:我正在寻找一种仅使用一个类来实现此目标的方法,VehicleCollection返回汽车,SUV等的列表。
How can I know in the code that in this specific script the VehicleCollection::getVehicles() will return cars and not SUV? 我如何在代码中知道在此特定脚本中,VehicleCollection :: getVehicles()将返回汽车而不是SUV? Maybe I can have some logic the class checking from where it was called, or I send in the caller object as a parameter, then check which class it is and according to that get VehicleCollection::getVehicles() to return for examle SUV and not Car.
也许我可以从类的调用位置检查类的逻辑,或者我将调用者对象作为参数发送,然后检查它是哪个类,然后根据该get VehicleCollection :: getVehicles()返回例如SUV的类,而不是汽车。
You could try making your own collection type, which validates that everything is a vehicle, but also enforces they're all the same type of vehicle. 您可以尝试创建自己的集合类型,该集合类型可以验证所有东西都是车辆,还可以强制要求它们都是相同类型的车辆。
<?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.'
This has the added benefit that if you further extended, eg made a class SportsCar extends Car {}
, that SportsCar could go into your collection. 这样做还有一个好处,就是如果您进一步扩展(例如,将
class SportsCar extends Car {}
,SportsCar 可以进入您的收藏夹。
It was pointed out that I might have been misinterpreting your question. 有人指出,我可能一直在曲解你的问题。 If you're just trying to filter an array, this becomes a much simpler problem.
如果您只是尝试过滤一个数组,这将成为一个简单得多的问题。 I wouldn't bother to even implement a special class if that's the case - just pass a Closure into
array_filter
, which is quite readable and an easy pattern to follow elsewhere: 如果是这种情况,我什至不愿意实现一个特殊的类-只需将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; });
So in that example, the array of vehicles has an SUV, and once filtered, the $cars array has only the cars. 因此,在该示例中,车辆阵列具有SUV,并且一旦过滤,$ cars阵列仅具有汽车。 If you want to make that a class method, you could do something along the lines of:
如果要使该方法成为类方法,则可以执行以下操作:
public function getAllOfType($type)
{
return array_filter(
$this->vehicles,
function($vehicle) { return is_a($vehicle, $type); }
);
}
Then to grab only cars from your collection: 然后仅从您的收藏中抢购汽车:
$cars = $myVehicleCollection->getAllOfType('Car');
What about a static property in the parent class Vehicle that would look something like: 父类Vehicle的静态属性如下所示:
array( 'cars' => array(car instances),
'suvs' =>array(suv instances).
....
)
Then you would have to put logic in your constructors and destructors to add and remove the objects from this array. 然后,您将不得不在构造函数和析构函数中放入逻辑,以从此数组添加和删除对象。
Then you can get a list of all cars by calling Vehicle::thatArry['cars']
. 然后,您可以通过调用
Vehicle::thatArry['cars']
获得所有汽车的列表。 But of course you want to throw some nice getters and setters around that array. 但是,当然,您想在该数组周围抛出一些不错的getter和setter方法。
I haven't totally thought this through yet, it might need some tweaks. 我还没有完全考虑到这一点,可能需要进行一些调整。 But if its totally off, holla at me.
但是,如果它完全消失了,霍拉对我。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.