【问题标题】:Decorator Pattern with method relation具有方法关系的装饰器模式
【发布时间】:2018-03-25 18:04:05
【问题描述】:

我在PHP中使用了设计模式Decorator,但遇到了结构问题。

这是一个简单的例子来说明我的问题:

interface MyInterface {
    function showUsers($array);
    function showUser($i);
}

class MyCLass implements MyInterface {

    function showUsers($array)
    {
        foreach($array as $toto) {
            $this->showUser($toto);
        }
    }

    function showUser($i)
    {
        echo $i;
    }
}

class MyCLassDecorator implements MyInterface {

    private $inner;

    public function __construct(MyInterface $inner)
    {
        $this->inner = $inner;
    }

    function showUsers($array)
    {
        $this->inner->showUsers($array);
    }

    function showUser($i)
    {
        echo "User: $i";
    }
}

class MyCLassDecorator2 implements MyInterface {

    private $inner;

    public function __construct(MyInterface $inner)
    {
        $this->inner = $inner;
    }

    function showUsers($array)
    {
        $this->inner->showUsers($array);
    }

    function showUser($i)
    {
        $this->inner->showUser($i);
        echo " is wonderful";
    }
}

$myClass = new MyCLassDecorator2(new MyCLassDecorator(new MyCLass()));

$myClass->showUsers(["Alfred", "Bob", "Claire"]);

使用此代码,MyClassDecorator 和 MyClassDecorator2 的方法 showUser 将永远不会被调用。

我能做什么? 是否禁止调用同一类的另一个方法? (拆分我的代码不太方便) 还有另一种方法可以做到这一点吗? 我应该按方法创建一个接口吗?

非常感谢:)

编辑:

这是我最后使用的解决方案,虽然我不是很满意...

我不是在方法中而是在接口(服务)中拆分我的代码

这里是:

interface IShowUsers {
    function showUsers($array);
}
interface IShowUser {
    function showUser($user);
}

class Services {
    static $showUsers;
    static $showUser;
}

class MyShowUsers implements IShowUsers {

    function showUsers($array)
    {
        foreach($array as $toto) {
            Services::$showUser->showUser($toto);
        }
    }
}

class MyShowUser implements IShowUser {
    function showUser($user)
    {
        echo $user;
    }
}

class MyShowUserDecorator implements IShowUser {

    private $inner;

    public function __construct(IShowUser $inner)
    {
        $this->inner = $inner;
    }

    function showUser($user)
    {
        echo "User: ";
        $this->inner->showUser($user)
    }
}

class MyShowUserDecorator2 implements IShowUser {

    private $inner;

    public function __construct(MyInterface $inner)
    {
        $this->inner = $inner;
    }

    function showUser($user)
    {
        $this->inner->showUser($user);
        echo " is wonderful";
    }
}

$myClass = new MyShowUserDecorator2(new MyShowUserDecorator(new MyShowUser()));

Services::$showUsers = new MyShosUsers();
Services::$showUser = new MyShowUserDecorator2(new MyShowUserDecorator(new MyShowUser()));

Services::$showUsers->showUsers(["Alfred", "Bob", "Claire"]);

如果你有更好的解决方案,我会很高兴知道的 :)

当然,我使用装饰器模式在许多项目中以不同的方式使用这些装饰器,例如这些示例:

//no decorators
Services::$showUser = new MyShowUser();

//only the first
Services::$showUser = new MyShowUserDecorator(new MyShowUser());

//only the second
Services::$showUser = new MyShowUserDecorator2(new MyShowUser());

所以扩展似乎不是一个好的解决方案。

再次感谢您提供正确的方法:)

【问题讨论】:

    标签: php symfony decorator


    【解决方案1】:

    在我看来,您需要重新考虑一下。如果您可以清楚地了解您要完成的工作,那么我们可以提供更多见解。但要直接回答您的问题,您可以extend 类,然后override 方法。

    http://sandbox.onlinephpfunctions.com/code/61c33b0ce98631986134bf78efcd0391f9b9ab67

    <?php
    interface MyInterface {
        function showUsers($array);
        function showUser($i);
    }
    
    class MyCLass implements MyInterface {
    
        function showUsers($array = ["Alfred", "Bob", "Claire"])
        {
            foreach($array as $toto) {
                $this->showUser($toto);
            }
        }
    
        function showUser($i)
        {
            echo $i;
        }
    }
    
    // Extend the class in order to override the methods.
    class MyCLassDecorator extends MyCLass {
    
        // Also, try removing this method to see what it does. 
        function showUsers($array = [1,2,3])
        {
            foreach($array as $toto) {
                $this->showUser($toto);
            }
        }
    
        function showUser($i)
        {
            echo "c'est la fete chez $i";
        }
    }
    
    $myClass = new MyCLassDecorator();
    
    $myClass->showUsers();
    

    编辑

    不确定我是否清楚,但问题是您期望继承行为而不使用继承MyCLass 应该怎么知道MyCLassDecorator::showUser

    foreach($array as $toto) {
        // The issue is this line. You're mixing `decorator` and `inheritance`. 
        // You should re-think your design. This will not work.
        $this->showUser($toto);
    }
    

    【讨论】:

    • 是的,在这个小例子中,这将是一个很好的解决方法,但是我在 symfony 服务中遇到了这个问题,它具有更复杂的功能和更多的装饰封装。所以我需要保留装饰器模式以避免擦除覆盖。
    • 你没有正确使用装饰器模式并且你已经编辑了你的代码,所以我的例子现在已经过时了。您正在调用$this-&gt;inner-&gt;showUsers($array);,它在MyCLass 的实例上调用showUsers,这就是它不使用MyCLassDecorator::showUser 的原因。您必须 extend 类,以便它知道覆盖的方法,或者您需要正确使用装饰器模式。我看看能不能举个例子。
    • 我已经编辑了我的帖子,你现在可能会更好地理解我需要什么 :) 而且我确切地说我不知道​​在哪个顺序之前将使用装饰器。
    猜你喜欢
    • 2012-01-28
    • 2019-02-23
    • 2013-02-19
    • 2017-05-25
    • 2014-12-29
    • 1970-01-01
    • 1970-01-01
    • 2016-10-14
    • 2014-06-12
    相关资源
    最近更新 更多