代码之家  ›  专栏  ›  技术社区  ›  Noah Goodrich

重构以消除静态方法的代码气味

  •  4
  • Noah Goodrich  · 技术社区  · 16 年前

    对于我需要创建的每个域对象,我都有当前的基本结构:

    class Model_Company extends LP_Model
    {   
        protected static $_gatewayName = 'Model_Table_Company';
        protected static $_gateway;
        protected static $_class;
    
        public static function init()
        {
            if(self::$_gateway == null)
            {
                self::$_gateway = new self::$_gatewayName();
                self::$_class = get_class();
            }
        }
    
        public static function get() 
        {
            self::init();
    
            $param = func_get_arg(0);
    
            if($param instanceof Zend_Db_Table_Row_Abstract)
            {
                $row = $param;
            }
            elseif(is_numeric($param))
            {
                $row = self::$_gateway->find($param)->current();
            }
    
            return new self::$_class($row);
        }
    
        public static function getCollection()
        {
            self::init();
    
            $param = func_get_arg(0);
    
            if($param instanceof Zend_Db_Table_Rowset_Abstract)
            {
                $rowset = $param;
            }
            elseif(!$param)
            {
                $rowset = self::$_gateway->fetchAll();
            }
    
            $array = array ();      
    
            foreach ($rowset as $row)
            {
                $array[] = new self::$_class($row);
            }
    
            return $array;
        }
    }
    

    我最初尝试将静态方法重构到父lp_模型类中,但最终了解了“后期静态绑定”在PHP世界中的含义。

    我只是想知道是否有人对如何重构这段代码有建议,这样我就不必在我创建的每个域对象中重新声明相同的三个函数了?

    1 回复  |  直到 16 年前
        1
  •  3
  •   Bill Karwin    16 年前

    这个怎么样?

    <?php
    
    abstract class Model_Abstract
    {
        protected $_gatewayName = null;
        protected $_gateway = null;
    
        protected function _init()
        {
            $this->_gateway = new $this->_gatewayName();
        }
    
        protected function __construct($row = null)
        {
            $this->_init();
            if ($row) {
                $this->_data = $row;
            }
        }
    
        public static function getAbstract($class, $param)
        {
            $model = new $class();
            if($param instanceof Zend_Db_Table_Row_Abstract)
            {
                    $row = $param;
            }
            elseif(is_numeric($param))
            {
                    $row = $model->_gateway->find($param)->current();
            }
    
            return new $class($row);
        }
    
        public static function getAbstractCollection($class, $param = null)
        {
            $model = new $class();
            if($param instanceof Zend_Db_Table_Rowset_Abstract)
            {
                    $rowset = $param;
            }
            elseif($param === null)
            {
                    $rowset = $model->_gateway->fetchAll();
            }
    
            $array = array ();
    
            foreach ($rowset as $row)
            {
                    $array[] = new $class($row);
            }
    
            return $array;
        }
    
        abstract public static function get($param);
        abstract public static function getCollection($param = null);
    }
    
    class Model_Company extends Model_Abstract
    {
        protected $_gatewayName = 'Model_Table_Company';
    
        public static function get($param) {
            return self::getAbstract(__CLASS__, $param);
        }
    
        public static function getCollection($param = null) {
            return self::getAbstractCollection(__CLASS__, $param);
        }
    }
    
    class Model_Table_Company extends Zend_Db_Table_Abstract
    {
        protected $_name = 'company';
    }
    
    $model = Model_Company::get(1);
    print "Got an object of type ".get_class($model)."\n";
    
    $models = Model_Company::getCollection();
    print "Got ".count($models)." objects of type ".get_class($models[0])."\n";
    
    ?>
    

    不幸的是,要使函数易于调用,必须复制 get() getCollection() 在每个子类中。另一个选项是调用父类中的函数:

    $model = Model_Abstract::getAbstract('Model_Company', 1);
    print "Got an object of type ".get_class($model)."\n";
    
    $models = Model_Abstract::getAbstractCollection('Model_Company');
    print "Got ".count($models)." objects of type ".get_class($models[0])."\n";
    

    如果要执行该路由,可以重命名基类及其函数名。但关键是 必须在一个地方或另一个地方命名子类 :要么在子类中创建一个样板函数,就像在第一个示例中那样,要么在字符串中命名该类,就像在第二个示例中一样。