【问题标题】:Encapsulating and inheriting methods封装和继承方法
【发布时间】:2010-11-20 21:23:16
【问题描述】:

我想知道是否可以封装一个类的方法,然后在消费类中公开它们。例如(JFTR,我知道这段代码是错误的)

class Consumer{
        public function __construct($obj){
            $this->obj = $obj;
            }

        public function doCommand(){
            $this->obj->command();
            }
        }

     class Consumed{
         //I would make the constructor private, but to save space...
         public function __construct(){}
         private function command(){
             echo "Executing command in the context of the Consumer";
             }
         }

     $consumer = new Consumer(new Consumed);
     $consumer->doCommand();

     //just to reiterate, I know this throws an error

最终,我希望能够制作在单个控制类的上下文之外无法直接引用的组件。

【问题讨论】:

  • 你的意思是像 C++ 中的朋友类? en.wikipedia.org/wiki/Friend_class
  • 你不能同时拥有它,如果你将功能隐藏在私有方法中,那么它不能从外部调用。如果你以任何方式公开它(通过创建一个公共方法,然后调用私有方法),那么每个人都可以调用你的私有方法。
  • 上面的评论当然是关于 PHP 的 :) 朋友类可以工作,但 PHP 中没有这样的概念。
  • 对不起,我应该把 PHP 放在标题中。 @Anti Veeranna,是否有另一种方法可以实现我的建议?其他无法访问的类的单点访问?

标签: php oop inheritance visibility encapsulation


【解决方案1】:

当然可以,只需将这些方法设为protected,而不是private,并让Consumed 扩展自Consumer。不过我不确定这些好处。

【讨论】:

  • 防止直接访问他们的方法,并强制单点进入。从设计的角度来看,这很糟糕吗?
  • 可能是。我的意思是,Consumed 类基本上是不可测试的。没有公共接口的类的目的是什么?也许这表明你真的不需要那门课。访问限制并不一定能保证好的设计。您要解决的问题是什么?
  • 真的没有 - 我只是在研究这个主题。我正在滚动我自己的 MVC 作为该过程的一部分(我知道这是多余的,但有助于我学习的智力练习)过程。在我的表示层中,视图控制器使用一类对象将部分模板提供给主模板,我想防止直接访问该对象。我在查看策略/命令模式后考虑了一下——在我看到的示例中,可以直接访问消耗的组件——似乎单点入口只是作为一个原则点而受到尊重。跨度>
  • 推出自己的 MVC 很好,你会学到很多东西。至于其他部分,恐怕我不太了解对象的整体布线,因此我可以给出任何意见。根据我的经验,我注意到担心访问控制会降低工作效率。我假设你想了解设计模式和其他东西,但试着假设你图书馆的虚拟用户已经足够成熟,不会自欺欺人。创建一个好的、可扩展的设计,没有人会想要访问应该保护的东西。如果他们这样做,他们就要为自己的行为负责
【解决方案2】:

可以__calldebug_backtrace模拟类似的东西。

<?php
class Consumer{
  public function __construct($obj){
    $this->obj = $obj;
  }

  public function doCommand(){
    $this->obj->command();
  }
}

class Consumed {
  // classes that are aloowed to call private functions
  private $friends = array('Consumer');

  public function __construct(){}
  private function command() {
    echo "Executing command in the context of the Consumer. \n";
  }

  public function __call($name, $arguments) {
    $dt = debug_backtrace();
    // [0] describes this method's frame
    // [1] is the would-be frame of the method command()
    // [2] is the frame of the direct caller. That's the interesting one.
    if ( isset($dt[2], $dt[2]['class']) && in_array($dt[2]['class'], $this->friends) ) {
      return call_user_func_array(array($this,$name), $arguments);
    }
    else {
      die('!__call()');
    }
  }
}

$c = new Consumed;
$consumer = new Consumer($c);
$consumer->doCommand();

echo 'and now without Consumer: '; 
$c->command();

打印

Executing command in the context of the Consumer. 
and now without Consumer: !__call()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-09
    • 2012-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多