0

私はポリモーフィズムに関する SO の投稿を数多く読みました。また、http://net.tutsplus.com/tutorials/php/understanding-and-applying-polymorphism-in-php/にある他の非常に優れた投稿も読みました。

---EDIT--- 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 を実装する場合、心に留めておくことが非常に重要だと思うことの 1 つは、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 の format 関数では、次のようになります。

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;
}

プロファイルクラスは次のようにする必要があります。

class Profile
{

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

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

}

後でさらに 10 種類のプロファイルがある場合は、プロファイル リストを拡張として使用して、PDF 形式の関数を簡単に呼び出すことができます。

于 2012-10-16T06:12:20.077 に答える