使用多态时如何抽象任务?

时间:2012-10-16 04:59:31

标签: php polymorphism

我已经阅读了很多有关多态性的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);

3 个答案:

答案 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格式功能作为扩充。

相关问题