0

我已经阅读了许多关于多态性的 SO 帖子,以及http://net.tutsplus.com/tutorials/php/understanding-and-applying-polymorphism-in-php/上的另一篇非常好的帖子好东西!

---编辑--- 在 PDFFormatter 类中,我必须使用 (instanceof) 来确定是否应在返回的数据中包含某些代码,因为我在格式化程序中对各个字段名称进行了硬编码。我怎样才能抽象出这种责任?我假设这不是最好的方法

我也试图传递不同类型的配置文件进行格式化。另请注意,可以有许多格式化程序类型。提前非常感谢!请只使用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);
4

3 回答 3

1

我会让 Profile 成为一个抽象类并定义一种机制来从中获取属性,无论它是什么“类型”的配置文件。

Profile 类可能有一个获取属性的方法(已经设置,可能在构造它时),可能使用魔法方法。因此,任何扩展 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原则。

在抽象类时添加特性和行为可能感觉很“自然”,但仅仅添加它们并不是一个好主意,因为“你认为”你可能在特性中需要它们。因此,请三思是否需要添加方法或功能以及何时添加。

于 2012-10-16T05:21:46.693 回答
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 条件。

于 2012-10-16T05:24:12.857 回答
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;
}

而且profile类一定是这样的,

class Profile
{

    public static function format($profileData)
    {
        return PDFFormatter::format($profileData);
    }

    public static function getProfileSpecificFormat($date)
    {
        return "Graduation Date: $date<br />";
    }

}

以后如果你有10种以上的Profiles,你可以很容易的调用PDF格式函数,使用profile list作为补充。

于 2012-10-16T06:12:20.077 回答