我有一个名为Assembly
的类,它隐藏了底层产品的实现。 ProductA
可以有一组getter,ProductB
可以有另一组。
虽然PHP非常宽容,如果我不混淆产品和吸气剂,我的代码会起作用,但是当我把Assembly
与ProductA
混为一谈时,没有提供任何保护措施,然后使用来自ProductB
的getter。
另外,我的IDE确实知道这两个类中的方法,因此当我使用Assembly
中的getter在Product
内部工作时,没有提供自动完成功能。
我想要更多防弹代码,Assembly
知道或知道当前托管的Product
子类型。有办法吗?
以下示例
class Assembly
{
private $product;
public function setProduct(Product $product) {
$this->product = $product;
}
public function getA() {
return $this->product->getA();
}
public function getB() {
return $this->product->getB();
}
}
class Product { }
class ProductA extends Product
{
public function getA() {
return "A";
}
}
class ProductB extends Product
{
public function getB() {
return "B";
}
}
//set assembly
$assembly = new Assembly();
//define product sub-type
$product = new ProductB();
//place product into assembly
$assembly->setProduct($product);
//assembly has no clue which subtype it has
print $assembly->getB(); // "B"
print $assembly->getA(); // prints nothing
界面建议
interface CompositeProductInterface
{
public function getA();
public function getB();
}
//update code in Assembly to:
public function setProduct(CompositeProductInterface $product)
{
$this->product = $product;
}
这让我在我的IDE中自动完成,这很好,但不能解决我的其他问题。此外,我将一些东西拼凑成一个单一的“复合”产品有点怪异......这看起来更像是一种解决方法。在我的具体情况下,我有两个非常相似的产品,在一些微小的东西,如一些属性上有所不同。
真实世界示例
产品型号A和B都有一个工程图,其中列出了用于识别各种产品尺寸的变量。两种产品的命名尺寸相似。例如,产品A上的M1表示产品B上的相同物理尺寸。但是,产品A具有产品B上不存在的特征,反之亦然。
如果仍然感觉太假设,实际图纸上的实际尺寸列为 B2 和 B3 。这些尺寸(B2,B3)不存在于其他产品型号上。我希望能够使用汇编构造列出图形上的变量,包括M1,B2,B3等。我可以用
这样做print $assembly->getM1(); //works for both products
print $assembly->getB2(); //works for one product only
print $assembly->getB3(); //same as above
目标
目标是让一个类(程序集)负责列出命名维度变量,每个产品只知道自己。所以
答案 0 :(得分:1)
我觉得这不是正确的解决方案,但您要求的方法可以通过以下方式实现。
get_class($product);
会告诉你哪个班级$product
。这将导致以下代码:
private $product;
private $productClass;
public function setProduct(Product $product) {
$this->product = $product;
$this->productClass = get_class($product);
}
或者:
public function getProductClass(){
return get_class($this->$product);
}
这可能导致类似的检查:
public function getA() {
if($this->productClass === "ProductA")
return $this->product->getA();
}
记录在:
答案 1 :(得分:0)
我知道已有一个已接受的答案,但我想提供一个更正确的OOP方法。
实际的解决方案只会因为PHP使用实际类型而不是从方法签名类型限制对象的范围。
为避免复杂性分歧,我不建议使用每次添加另一个(新产品类型)时必须在类(程序集)中添加一些代码的代码。
在您的情况下,我会使用pattern adapter。
这是你的适配器:
interface AssemblyInterface
{
function getA();
function getB();
}
class AssemblyA implements AssemblyInterface
{
private $product;
public function setProduct(ProductA $product) {
$this->product = $product;
}
public function getA() {
return $this->product->getA();
}
public function getB() {
return;
}
}
class AssemblyB implements AssemblyInterface
{
private $product;
public function setProduct(ProductB $product) {
$this->product = $product;
}
public function getA() {
return;
}
public function getB() {
return $this->product->getB();
}
}
在这里你的适应者:
class ProductA
{
public function getA() {
return "A";
}
}
class ProductB
{
public function getB() {
return "B";
}
}
现在,您可以使用pattern factory来检索程序集。
这是你的创作者:
interface AssemblyCreatorInterface
{
function isSupportingProduct($product);
function createAssembly($product);
}
class AssemblyCreatorA implements AssemblyCreatorInterface
{
public function isSupportingProduct($product) {
return $product instanceof ProductA;
}
public function createAssembly($product) {
return new AssemblyA($product);
}
}
class AssemblyCreatorB implements AssemblyCreatorInterface
{
public function isSupportingProduct($product) {
return $product instanceof ProductB;
}
public function createAssembly($product) {
return new AssemblyB($product);
}
}
这里是装配工厂:
class AssemblyFactory
{
private $assemblyCreators = array();
public function addCreator(AssemblyCreatorInterface $assemblyCreator) {
$this->assemblyCreators = $assemblyCreator;
}
public function get($product) {
// Find the good creator for your product.
foreach ($this->assemblyCreators as $assemblyCreator) {
if ($assemblyCreator->isSupportingProduct($product)) {
// Create and return the assembly for your product.
return $assemblyCreator->createAssembly($product);
}
}
throw new \InvalidArgumentException(sprintf(
'No available assembly creator for product "".',
get_class($product);
));
}
}
最后,这是一个程序示例:
// Process dependency injection.
// (you should be able to do it only once in your code)
$assemblyCreatorA = new AssemblyCreatorA();
$assemblyCreatorB = new AssemblyCreatorB();
$assemblyFactory = new AssemblyFactory();
$assemblyFactory->addCreator($assemblyCreatorA);
$assemblyFactory->addCreator($assemblyCreatorB);
// Retrieve assemblies from products.
$productA = new ProductA();
$productB = new ProductB();
$assemblyA = $assemblyFactory->get($productA);
$assemblyB = $assemblyFactory->get($productB);
$assemblyA->getA(); // 'A'
$assemblyA->getB(); // null
$assemblyB->getA(); // null
$assemblyB->getB(); // 'B'
这是一些代码,但这会尊重您的方法签名,并将处理日益复杂的应用程序。使用此解决方案,如果您有100种不同的产品类型,则每种产品类型将独立于其他产品类型(一个类Assembly
,一个类Product
和一个类Creator
)。如果您必须为每个吸气剂编码每个产品的特异性,请想象您的汇编类!