Php 我如何在这个场景中实现抽象?
我有一个父类Php 我如何在这个场景中实现抽象?,php,oop,inheritance,abstraction,Php,Oop,Inheritance,Abstraction,我有一个父类产品和两个子类:牙刷和电锯。它们的设置如下所示 下面是父类: class Product { protected $productid; protected $type; public function __construct( $productid ) { $this->productid = $productid; // Performs a lookup in the database and then popul
产品
和两个子类:牙刷
和电锯
。它们的设置如下所示
下面是父类:
class Product {
protected $productid;
protected $type;
public function __construct( $productid ) {
$this->productid = $productid;
// Performs a lookup in the database and then populates the $type property
}
}
。。下面是孩子们:
class Toothbrush extends Product {
public function getPrice() {
return 5; // returning an integer for simplicity; there's a calculation going on here
}
}
class Chainsaw extends Product {
public function getPrice() {
return 1000; // in USD
}
}
我想遍历$productid
的列表,并获得相应的物品价格,而不管它们是电锯
还是牙刷
es
问题(或者是它吗?)
现在我一遍又一遍地听说父类不应该依赖子类来实现功能(是的,我和其他许多人都读过)
这就是为什么我认为我目前使用的解决方案(以下)不是最佳的:
class Product {
...
public function getPrice() {
switch($this->type) {
case 'toothbrush':
$theproduct=new Toothbrush($this->productid);
return $theproduct->getPrice();
break;
case 'chainsaw':
$theproduct=new Chainsaw($this->productid);
return $theproduct->getPrice();
break;
}
}
}
我可以明显地感觉到这里有些疏忽(想到当我得到30种不同的产品类型时会发生什么,我不寒而栗)。我读过关于抽象、接口和继承的书,但不知道在这个场景中哪一个可以工作
谢谢大家!
编辑
看到了很多答案,但还没有一个找到答案。这里是要点:
如果只有productid,如何调用子方法?(在上面的场景中,
Product
类从构造函数中的数据库中检索类型,并相应地填充$type
属性。家长不应依赖其子女是正确的,这就是为什么您也在家长中定义它
class Product {
protected $productid;
public function getPrice() {
return NULL; // or 0 or whatever default you want
}
}
class Toothbrush extends Product {
public function getPrice() {
return 5; // in USD
}
}
class Chainsaw extends Product {
public function getPrice() {
return 1000; // in USD
}
}
class Fake extends Product {
}
$f = new Fake();
var_dump($f->getPrice());
现在,无论子级是否定义getPrice()方法,代码都将始终有效
但也许使用类似于
class Product {
protected $productid;
protected $price;
protected $type;
public function __construct($id, $price, $type) {
$this->productid = $id;
$this->price = $price;
$this->type = $type;
}
public function getPrice() {
return $this->price;
}
}
$tooth = new Product(1, 5, 'Toothbrush');
$chain = new Product(2, 1000, 'Chainsaw');
好的,你可以阅读。另外,你可以在父对象上做它(以及获取它的方法),而不是在子对象上声明价格,然后在需要时在任何子对象中重写该方法
现在我一遍又一遍地听说父类不应该依赖子类来实现功能
没错。而且您的开关
将是一个不需要的依赖项,而调用getPrice
则不会,只要它在父类中定义为抽象方法并在子类中重写。那么父类就不需要知道具体的子类,仍然可以调用它们的方法。如果这听起来很奇怪,那么哦,你,阅读多态性,理解这个概念对于理解OOP很重要
但你的问题更深:
这里是要点:如果只有productid,我如何调用子方法?(在上面的场景中,Product类从构造函数中的数据库检索类型,并相应地填充$type属性)
显然,你从来没有创建过链锯或牙刷的实例。你不能用新产品创建一个产品,然后告诉它“现在你是一个链锯”.对象的实际类型是不可变的。您试图通过在产品内部创建一个新的链锯来解决这一问题,该产品本来应该是一个链锯,只是为了获取其价格。这是一个可怕的错误,我想您已经意识到了这一点
这就是为什么在注释中建议使用工厂模式。工厂是一个实例化对象并根据参数决定使用哪个子类型的类。它也是此类switch语句的有效位置
示例:
class ProductFactory
{
public function makeProduct($id)
{
$record = perform_your_database_lookup_here();
switch ($record['type']) {
case 'toothbrush':
return new Toothbrush($id, $record);
case 'chainsaw':
return new Chainsaw($id, $record);
}
}
}
$factory = new ProductFactory();
$product = $factory->makeProduct(123);
echo $product->getPrice();
为简单起见,我将数据库查找放在工厂中。更好的解决方案是将其与两个类完全分离,例如在负责与products表相关的所有数据库查询的ProductTableGateway
类中。工厂将只接收结果
顺便说一句,我还建议最终去掉这些子类。没有一家严肃的网上商店对每种产品类型都有硬编码的类,而是动态创建不同的属性集,并将不同的价格计算委托给其他类。但这是一个高级主题,现在太离谱了。目标在哪里ProductID的et列表来自?基类应该只有一个泛型的getPrice
方法,如果默认值没有意义,该方法将返回默认值,或者什么都不返回。在子类中重写getPrice
是完全正确的,并且符合多态性的概念。@Cups ProductID来自数据库选项卡恰当地称为产品。摆脱$type
属性,创建一个工厂方法,它可以生产牙刷或链锯(取决于其参数,即类型)。子类对我来说似乎是多余的。您可以简单地将产品数据传递到产品类中。为什么需要键入所有这些,而不只是在product
类中将getPrice
作为抽象函数?谢谢Hugo,但这似乎并不能解决我最初遇到的问题:如果我不知道如何获取价格w事先是什么类型的产品。@FloatingRock只需调用getPrice
。电锯的getPrice
方法的行为与牙刷的getPrice
方法不同。@Asad你能告诉我这是如何工作的吗?我看不出这是可行的。@FloatingRock我不完全确定你的意思。上面的代码演示了如何重写方法。只需实例化一把牙刷和一把电锯,然后试着从中获取价格。这是一个演示。呃,谢谢。但我已经经历了这一过程,无法理解它。如果我不能实例化一个抽象类,那么我到底该如何知道的类型呢>产品
是?(因为产品
的类型在构造函数中确定)完美答案。非常感谢@fab