我对OOP很陌生并且对如何最好地处理使用一个类名有疑问,但后来根据传递的参数在内部添加了该类的功能。
基本的故事是我有一个'item'类,它带有2个参数$ module和$ id。某些“模块”(但不是全部)将具有“item”类默认不包含的奇特功能。某些模块还希望覆盖item类中的一些方法。我的目标是能够从item类的__construct中调用模块的'item'类的扩展。我想拥有单一的“项目”课程。
我的第一个想法是在构造item类时创建模块的项扩展类的实例,然后,每当我调用item类中的方法时,我都会检查是否有该模块特定的实例和在该实例上调用该方法。
例如:
class item {
// Variable where I'll store the instance of the child class
var $child;
// Child class may call up item's constuct, I'll use this to avoid an infinite loop
var $child_initalized;
// Child called, guess we have to keep track of this so we don't get stuck in infite loops either.
var $child_called = 0;
// Example variables
var $id, $name;
function __construct($module,$id) {
if(!$this->child_initialized) {
$this->child_initialized = 1; // So we don't do this again and get stuck in an infite loop
$child_class = __CLASS__.'_'.$module;
if(class_exists($child_class)) {
$this->child = new $child_class($module,$id);
return;
}
}
// do normal class construction stuff here, such as setting $this->id and $this->name
$this->module = $module;
$this->id = $id;
}
// So we can catch child methods not in parent item class
function __call($name,$arguments) {
if($this->child) {
return $this->child->$name();
}
}
function id() {
$this->child_called = 0;
if($this->child) {
$this->child_called = 1;
return $this->child->id();
}
return $this->id;
}
}
class item_photos extends item {
function __construct($module,$id) {
$this->child_initialized = 1;
parent::__construct($module,$id);
}
function id() {
return "photo-".$this->id;
}
function photo_width() {
return 250; // Just some sample value
}
}
$item = new item('photos',123);
print $item->id()."<br />"; // photo-123
print $item->photo_width()."<br />"; // 250
无论如何,这只是一个简单的例子。但是,我的方法似乎......好吧,错了。有没有更好的方法来完成这个或者我应该重新思考我是如何构建一切的?你能提供的任何建议或想法都会很棒。
/ * ** * ** * ** * * 修改 * ** * ** * ** * * /
为了澄清,我的目标实际上是能够调用一个类(在我的示例中为“item”),并且基于传递给它的一个或多个参数,能够动态加载更多功能那些参数(在我的例子中,它是$ module)。但是这些额外的功能并不总是存在(所以我不能总是调用new item_photos而不是new item())。
这是一个更新的例子。在代码末尾调用$ item = new item('videos',456)是一些模块不具备额外功能的示例。
class item {
// Variable where I'll store the instance of the child class
public $child;
// Child class may call up item's constuct, I'll use this to avoid an infinite loop. Also to avoid when calling child class in methods.
public $child_initalized;
// Example variables
public $module, $id, $name;
function __construct($module,$id) {
if(!$this->child_initialized) {
$child_class = __CLASS__.'_'.$module;
if(class_exists($child_class)) {
$this->child = new $child_class($module,$id);
return;
}
}
// do normal class construction stuff here, such as setting $this->id and $this->name
$this->module = $module;
$this->id = $id;
}
// So we can catch child methods not in parent item class
function __call($name,$arguments) {
if($this->child) {
return $this->child->$name();
}
}
function id() {
$this->child_initalized = 0;
if($this->child) {
$this->child_initalized = 1;
return $this->child->id();
}
return $this->id;
}
}
class item_photos extends item {
function __construct($module,$id) {
$this->child_initialized = 1;
parent::__construct($module,$id);
}
function id() {
return "photo-".$this->id;
}
function photo_width() {
return 250; // Just some sample value
}
}
$item = new item('photos',123);
print "photo id: ".$item->id()."<br />"; // photo-123
print "photo size: ".$item->photo_width()."<br />"; // 250
$item = new item('videos',456);
print "video id: ".$item->id()."<br />"; // 456
print "video size: ".$item->photo_width()."<br />"; // nothing (that method doesn't exist here)
/ * ** * ** * ** * 编辑2 * ** * ** * *** /
仍在苦苦挣扎。我调查了抽象工厂,他们似乎不会工作。如果我正确理解它们,我必须声明抽象类中的所有方法都很棘手,因为模块会扩展item类,所以我不会知道所有的方法。另外,似乎我必须调用'item_photos'或'item_videos'而不仅仅是'item',这正是我想要避免的。更不用说在我的例子中,item_videos甚至不存在。
鉴于我的目标是调用一个类,然后在类__construct中,根据$ module确定是否需要包含任何额外的功能,我想出了这个。
基本上什么'item'类被移动到新的'item_core'。旧项目类现在只确定要使用的类,模块的项类(如果存在)(例如:item_photos)或核心项类(item_core)。在我初始化其中一个类之后,我存储实例并在每次调用方法时使用它(通过__call,让我知道为什么使用__call是不好的。)
class item {
// Instance of the core class or module class
private $instance;
function __construct($module,$id) {
$class = __CLASS__;
$class_core = $class.'_core';
$class_module = $class.'_'.$module;
// Module class
if(class_exists($class_module)) $this->instance = new $class_module($module,$id);
// Core class
else $this->instance = new $class_core($module,$id);
}
// Catch all calls, redirect accordingly
function __call($name,$arguments) {
if($this->instance) {
if(method_exists($this->instance,$name)) return $this->instance->$name();
}
}
}
class item_core {
public $module, $id;
function __construct($module,$id) {
$this->module = $module;
$this->id = $id;
}
function id() {
return $this->id;
}
}
class item_photos extends item_core {
function __construct($module,$id) {
parent::__construct($module,$id);
}
function id() {
return "photo-".$this->id;
}
function photo_width() {
return 250; // Just some sample value
}
}
$item = new item('photos',123);
print "photo id: ".$item->id()."<br />"; // photo-123
print "photo size: ".$item->photo_width()."<br />"; // 250
$item = new item('videos',456);
print "video id: ".$item->id()."<br />"; // 456
print "video size: ".$item->photo_width()."<br />"; // nothing (that method doesn't exist in the videos module)
任何人都会发现有任何问题或者无论如何都要改进它?对我来说似乎有点不对。
/ * *** 编辑3 ** * **** /
好吧,在我看来,我想做的事情是能够返回一个不同于我调用的实例。所以,调用新项目($ module,$ id);,但是如果$ module == photos(在我的例子中)我想要返回一个新的item_photos($ module,$ id);的实例。到目前为止,我已经提出了两种可能的解决方案。
首先是我在编辑2(见上文)中概述的内容。
第二个选项是简单地调用一个函数(可能是'item')并在那里返回正确的对象实例(因为函数可以返回你想要的任何对象实例,而类构造函数只返回它自己的类的一个实例)。所以(基本例子):
function item($module,$id) {
$class_module = 'item_'.$module;
// Module class
if(class_exists($class_module)) return new $class_module($module,$id);
// Core class
else return new item($module,$id);
}
class item{..}
class item_photos{..}
$item = item('photos',123);
print $item->id(); // photo-123
我不确定我喜欢混合函数/类,但它很简单。
思想?
答案 0 :(得分:2)
不是在内部创建子类,而是应该在外部创建子类并将其注入item
类(依赖注入是您可能想要查找的内容)。您可能希望在控制器中使用工厂执行此操作。 __call
的使用也有点阴暗,打破了界面。我不确定为什么你需要item_photos
周围的抽象级别..你可以自己使用该对象。
答案 1 :(得分:2)
看起来您正在尝试实施的工作可以通过工厂设计模式实现。简而言之,当您想要传递一堆配置选项并获得代表您想要使用的对象的某些内容时,该模式很好。而不是尝试从内部更改Item类,为什么不创建一个返回新对象的ItemFactory类。例如,你向工厂索要一张照片或视频,它会返回一个Photo类或一个Video类(从一个通用的Item类扩展而来),它只有它需要的东西而且没有额外的东西。
这篇文章使用PHP示例更详细地解释了模式:http://sourcemaking.com/design_patterns/abstract_factory/php/2
答案 2 :(得分:1)
我认为你错了。
假设你要实现一个类A
。还有一个类B
,它与A
共享一些共同属性但具有更多功能。然后是一个班级C
,依此类推......
我是这样做的:
BasicItem
类。 (你甚至可能不会使用这个类本身,但只是将它用于你的......“衍生”类)A
,B
基于其他任何类别(使用继承)。