我已经阅读了很多有关多态性的SO帖子,以及http://net.tutsplus.com/tutorials/php/understanding-and-applying-polymorphism-in-php/好的东西中另一个非常好的帖子!
--- --- EDIT 在PDFFormatter类的内部,我不得不使用(instanceof)来确定返回的数据中是否应包含某些代码,因为我在格式化程序中对各个字段名称进行了硬编码。我该如何抽象出这个责任呢? 我认为这不是最好的方式
我也试图传递不同类型的配置文件进行格式化。另请注意,可以有许多格式化程序类型。非常感谢sooooooo!请PHP!谢谢!
文件1. FormatterInterface.php
interface FormatterInterface
{
public function format(Profile $Profile);
}
文件2. PDFFormatter.php
class PDFFormatter implements FormatterInterface
{
public function format(Profile $Profile)
{
$format = "PDF Format<br /><br />";
$format .= "This is a profile formatted as a PDF.<br />";
$format .= 'Name: ' . $Profile->name . '<br />';
if ($Profile instanceof StudentProfile) {
$format .= "Graduation Date: " . $Profile->graduationDate . "<br />";
}
$format .= "<br />End of PDF file";
return $format;
}
}
文件3. Profile.php
class Profile
{
public $name;
public function __construct($name)
{
$this->name = $name;
}
public function format(FormatterInterface $Formatter)
{
return $Formatter->format($this);
}
}
文件4. StudentProfile.php
class StudentProfile extends Profile
{
public $graduationDate;
public function __construct($name, $graduationDate)
{
$this->name = $name;
$this->graduationDate = $graduationDate;
}
}
文件5. index.php
//Assuming all files are included......
$StudentProfile = new StudentProfile('Michael Conner', 55, 'Unknown, FL', 'Graduate', '1975', 'Business Management');
$Profile = new Profile('Brandy Smith', 44, 'Houston, TX');
$PDFFormatter = new PDFFormatter();
echo '<hr />';
echo $StudentProfile->format($PDFFormatter);
echo '<hr />';
echo $Profile->format($PDFFormatter);
答案 0 :(得分:1)
我会使Profile成为一个抽象类,并定义一个从中获取属性的机制,无论它是什么类型的配置文件。
Profile类可能有一个方法来获取属性(已经设置,可能在构造它时),也许使用magic methods。因此,任何扩展Profile的对象都有一种根据设置属性“格式化”自身的机制。
我希望它有所帮助并使我自己清楚。
当我试图实现我认为你想要实现的那种行为时,我提出了这些代码。
首先,让我们为格式化程序定义一个接口:
/**
* Formatter interface
*
* @category Formatter
* @package Formatter
* @author Saul Martinez <saul@sharkwebintelligence.com>
* @copyright 2012 Shark Web Intelligence
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @version 1.0
* @link http://www.sharkwebintelligence.com
*/
interface IFormatter
{
/**
* Object formatting.
*
* @return string
*/
public function format();
}
但没什么特别的。现在让我们定义一种帮助器来保存字段或属性,在本例中是一个配置文件:
/**
* Profile field.
*
* @category Formatter
* @package Profile
* @subpackage Field
* @author Saul Martinez <saul@sharkwebintelligence.com>
* @copyright 2012 Shark Web Intelligence
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @version 1.0
* @link http://www.sharkwebintelligence.com
*/
class ProfileField
{
/**
* @var string $name Field name.
*/
public $name;
/**
* @var mixed $value Field value.
*/
public $value;
/**
* Factory method to create a profile field.
*
* @param string $name Field name.
* @param mixed $value Field value.
*
* @return ProfileField
*/
public static function factory($name, $value)
{
$field = new self();
$field->name = $name;
$field->value = $value;
return $field;
}
/**
* Format the profile field.
*
* @return string
*/
public function __toString()
{
return $this->name . ': ' . $this->value . PHP_EOL;
}
}
下一堂课Profile
,我试图让它变得有点灵活:
/**
* Profile.
*
* @category Formatter
* @package Profile
* @author Saul Martinez <saul@sharkwebintelligence.com>
* @copyright 2012 Shark Web Intelligence
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @version 1.0
* @link http://www.sharkwebintelligence.com
*/
abstract class Profile implements IFormatter
{
/**
* @var array $fields Profile fields.
*/
public $fields;
/**
* Constructor.
*
* - Set options.
*
* @param array $options Profile options.
*/
public function __construct($options)
{
if (is_array($options)) {
$this->setOptions($options);
}
}
/**
* Format implementation.
*
* @return string
*/
public function format()
{
$output = '';
foreach ($this->getFields() as $field) {
$output .= $field;
}
return $output;
}
/**
* Adds a field to the fields list.
*
* @param ProfileField $field Field to add.
*
* @return Profile Provides a fluent interface.
*/
public function addField(ProfileField $field)
{
$this->fields[] = $field;
return $this;
}
/**
* Set profile fields.
*
* @param array $fields Profile fields.
*
* @return Profile Provides a fluent interface.
*/
public function setFields(array $fields)
{
$this->fields = $fields;
return $this;
}
/**
* Get profile fields.
*
* @return array
*/
public function getFields()
{
return $this->fields;
}
/**
* Set profile options.
*
* @param array $options Profile options.
*
* @return Profile Provides a fluent interface.
*/
public function setOptions(array $options)
{
$methods = get_class_methods($this);
foreach ($options as $name => $value) {
$method = 'set' . ucfirst($name);
if (in_array($method, $methods)) {
$this->$method($value);
}
}
return $this;
}
}
最后,学生配置文件类,如果要添加特定行为,可以覆盖任何Profile
类方法:
/**
* Student profile.
*
* @category Formatter
* @package Profile
* @subpackage Student
* @author Saul Martinez <saul@sharkwebintelligence.com>
* @copyright 2012 Shark Web Intelligence
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @version 1.0
* @link http://www.sharkwebintelligence.com
*/
class StudentProfile extends Profile
{
}
现在,您只需要实例化StudentProfile
类并向其中添加一些字段:
$studentProfile = new StudentProfile(
array(
'fields' => array(
ProfileField::factory('Name', 'Buddy'),
ProfileField::factory('Birth date', '1983/05/05'),
ProfileField::factory('Graduation date', '2000/01/01'),
),
)
);
echo $studentProfile->format();
希望它有所帮助,我清楚自己。
我只是想补充一点,在用任何语言实现OOP时,我认为要记住的一件事是YAGNI原则。
在抽象类时添加功能和行为可能会“自然”,但添加它们并不是一个好主意,因为“你认为”你可能需要在功能中使用它们。因此,请三思而后行是否需要添加方法或功能。
答案 1 :(得分:1)
我应该做以下事情:
使配置文件成为抽象,并定义和抽象方法formatSpecific()
abstract class Profile {
abstract protected function formatSpecific();
...
}
在班级学生:
protected function formatSpecific() {
$format .= "Graduation Date: " . $this->graduationDate . "<br />";
}
在PDFFormatter类的格式函数中:
public function format(Profile $Profile)
{
$format = "PDF Format<br /><br />";
$format .= "This is a profile formatted as a PDF.<br />";
$format .= 'Name: ' . $Profile->name . '<br />';
$format .= $Profile->formatSpecific();
$format .= "<br />End of PDF file";
return $format;
}
通过这种方式,您可以摆脱instanceOf条件。
答案 2 :(得分:0)
最好使用Late Static binding
您的格式化功能可以更改为静态,
public static function format($profileData)
{
$format = "PDF Format<br /><br />";
$format .= "This is a profile formatted as a PDF.<br />";
$format .= 'Name: ' . $profileData['name'] . '<br />';
$format .= static::getProfileSpecificFormat($profileData['date'] );
$format .= "<br />End of PDF file";
return $format;
}
简介类必须是这样的,
class Profile
{
public static function format($profileData)
{
return PDFFormatter::format($profileData);
}
public static function getProfileSpecificFormat($date)
{
return "Graduation Date: $date<br />";
}
}
稍后,如果您还有10种配置文件,则可以使用配置文件列表轻松调用PDF格式功能作为扩充。