PHP OOP设计:一个对象可以有几个“模式”。 我该如何定义它们?

I have a Display object that handles HTML output of the script. It has a mode property, which defines many aspects of how the output is generated. There are several modes, and I will probably add more later. Each mode implies it's own parameters. For example, an author mode would imply an authorID. A search mode would imply a Search object as a parameter, which would contain query information. A comment mode would imply a postID and commentID parameters.

So, a mode has a name and some number of parameters, depending on the name.

I decided to create a Display_Mode object, which has two properties: name and parameters. But how do I assign parameters to names? So that if I have a comment mode, it would neccessarily mean that there are postID and commentID parameters?

My current solution is this:

class display_mode{
    public $name;
    public $params;

    public function __construct($name)
        {
        $this->name = $name;
        switch ($this->name){
            case 'comment':
                $this->params = array('postID', `commentID`);
                break;
            case 'author':
                $this->params = array('authorID');
            }
            //etc..
        }
    }

This seems a bit messy. Is there a better way?

UPD: given answers led me to ask another question, concerning the whole design, which also provides context for this one.

You're better off abstracting the common functionality of the Display_Mode class into an abstract base class or interface and then defining each individual mode as a class that inherits from the base class (or implements the interface).

These specialised mode classes would then explicitly define the parameters they require in their constructors and/or methods, and would be responsible for producing the output that each "mode" requires.

It's difficult to give more specific advice than this without knowing exactly what your Display_Mode class is supposed to do, however.


The idea here is that you should avoid do-it-all classes in OOP, preferring small, self-contained classes each with a single purpose. By giving each mode its own class that can independently render its content, you're making it easy to change the way display modes work or add new ones. All you have to do is add a new class.

This is known as loose coupling.

The description is kinda confusing, but I would create an adapter for each possible "parameter" of Display. This adapter could provide single interface, independently of the the resource that you want to display.

$parameter = new UnknownPrameter;

$adapterFactory = new AdapterFactory;
$parameter = $adapterFactory->build( $parameter );

$display->present( $parameter );

Where AdapterFactory::build() create a wrapper for the specific type of parameter, that you supplied. The returned instance is a container for that parameter.

This approach would also prevent the computation from accumulating in the constructor, which would make the code harder to test/expand.

@Will Vousden already gave you the answer. This is a quick example of how to approach your problem.

abstract class DisplayMode {
    protected $_params = array();

    public function __construct(array $params) {
        $this->_params = $params;
    }

    public function hasParameter($key) {
        if (array_key_exists($key, $this->_params)) {
            return true;
        }
        return false;
    }

    public function setParameters(array $params) {
        $this->_params = $params;
        return $this;
    }

    public function getParameters() {
        return $this->_params;
    }
}

class CommentMode extends DisplayMode {
    public function getCommentId() {
        if ($this->hasParameter('comment_id')) {
            return $this->_params['comment_id'];
        }    
        return null;
    }

    public function getPostId() {
        if ($this->hasParameter('post_id')) {
            return $this->_params['post_id'];
        }    
        return null;
    }
}

class AuthorMode extends DisplayMode {
    public function getAuthorId() {
        if ($this->hasParameter('author_id')) {
            return $this->_params['author_id'];
        }    
        return null;
    }
}

$comment = new CommentMode(array('post_id' => 4, 'comment_id' => 2));
$author = new AuthorMode(array('author_id' => 3));

// example

print $comment->getCommentId() . ' -  ' . $comment->getPostId() . '  - ' . $author->getAuthorId();