【问题标题】:Common methods and different constructors常用方法和不同的构造函数
【发布时间】:2017-05-26 05:38:52
【问题描述】:

我正在使用自定义 MVC php Web 应用程序。 这是我此刻所拥有的:

  • 所有控制器都应扩展的“CtrlBase”类。
  • 而且由于应用程序有 3 个不同的部分(应用程序(我将在此处使用应用程序一词))从用户的角度来看是独立的,但很多功能在 3 个应用程序之间共享,我有一个特定的控制器每个扩展“CtrlBase”的应用程序:CtrlBaseAdmin、CtrlBaseCms、CtrlBaseWeb。
    • 在此级别应考虑的 3 个不同控制器之间的主要区别在于构造函数。
    • 我有一个用于用户的 CRUD 控制器,它在所有 3 个应用程序中具有相同的功能,除了每个都根据应用程序扩展特定的基本控制器。

所有三个应用程序的所有方法:索引、编辑、添加和删除都是相同的,但父构造函数不同,并且同一应用程序的所有控制器都扩展了相同的父控制器。

所以我的问题是如何避免这种代码重复(索引、编辑、添加和删除功能对于三个应用程序中的所有用户控制器都是相同的)?

由于描述不是很清楚,我添加一个代码演示,您可以使用它更好地理解它。

首先,我们有一个具有所有通用功能的 Base 控制器:

/**
 * Controller Base
 */
class CtrlBase {

   /**
    * Class constructor
    */
   protected function __construct() {
      echo __METHOD__ . PHP_EOL;
   }

}

然后我们有三个基本控制器扩展这个基本控制器并添加特定于每个应用程序的东西。显然,这是当前应用程序中所有控制器扩展的基本控制器。所以我们有 3 个特定于应用的基本控制器:

CtrlBaseAdmin.php

require_once('CtrlBase.php');

class CtrlBaseAdmin extends CtrlBase {

   function __construct() {
      parent::__construct();
      echo __METHOD__ . ": " . "processing some stuff specific to admin." . PHP_EOL;
   }

}

CtrlBaseCms.php

require_once('CtrlBase.php');

class CtrlBaseCms extends CtrlBase {

   function __construct() {
      parent::__construct();
      echo __METHOD__ . ": " . "processing some stuff specific to cms." . PHP_EOL;
   }

}

CtrlBaseWeb.php

require_once('CtrlBase.php');

class CtrlBaseWeb extends CtrlBase {

   function __construct() {
      parent::__construct();
      echo __METHOD__ . ": " . "processing some stuff specific to web." . PHP_EOL;
   }

}

这很好用。因为到目前为止我所做的只是在父类中制作基本控制器的通用功能,并且我将给定应用程序的特定内容保留在其特定的基本控制器中。当我有一个特定于应用程序且未在其他地方使用的控制器时,一切都很好:

CtrlNotCommon.php

require_once('CtrlBaseWeb.php');

class CtrlNotCommon extends CtrlBaseWeb {

   function __construct() {
      echo __METHOD__ . ": " . "This controller functionality is specific to web only and not used elsewhere. So no problem here." . PHP_EOL;
      parent::__construct();

   }

}

但现在看看这三个控制器在三个应用程序中具有共同的功能:

CtrlCommonFeatureAdmin.php

require_once('CtrlBaseAdmin.php');

class CtrlCommonFeatureAdmin extends CtrlBaseAdmin {

   function __construct() {
      echo __METHOD__ . ": " . "This controller functionality is (methods index and add) common to web, admin and cms." . PHP_EOL;
      parent::__construct();  
   }

   function index() {
      echo __METHOD__ . " is a duplication of " . __FUNCTION__ . " method in CtrlCommonFeatureWeb and CtrlCommonFeatureCms." . PHP_EOL;
   }

   function add() {
      echo __METHOD__ . " is a duplication of " . __FUNCTION__ . " method in CtrlCommonFeatureWeb and CtrlCommonFeatureCms." . PHP_EOL;
   }   

}

CtrlCommonFeatureCms.php

require_once('CtrlBaseCms.php');

class CtrlCommonFeatureCms extends CtrlBaseCms {

   function __construct() {
      echo __METHOD__ . ": " . "This controller functionality (methods index and add) is  common to web, admin and cms." . PHP_EOL;
      parent::__construct();  
   }

   function index() {
      echo __METHOD__ . " is a duplication of " . __FUNCTION__ . " method in CtrlCommonFeatureAdmin and CtrlCommonFeatureWeb." . PHP_EOL;
   }

   function add() {
      echo __METHOD__ . " is a duplication of " . __FUNCTION__ . " method in CtrlCommonFeatureAdmin and CtrlCommonFeatureCms." . PHP_EOL;
   }   

}

CtrlCommonFeatureWeb.php

require_once('CtrlBaseWeb.php');

class CtrlCommonFeatureWeb extends CtrlBaseWeb {

   function __construct() {
      echo __METHOD__ . ": " . "This controller functionality is (methods index and add) common to web, admin and cms." . PHP_EOL;
      parent::__construct();  
   }

   function index() {
      echo __METHOD__ . " is a duplication of " . __FUNCTION__ . " method in CtrlCommonFeatureAdmin and CtrlCommonFeatureCms." . PHP_EOL;
   }

   function add() {
      echo __METHOD__ . " is a duplication of " . __FUNCTION__ . " method in CtrlCommonFeatureAdmin and CtrlCommonFeatureCms." . PHP_EOL;
   }   

}

正如您在此示例中看到的那样。函数索引和添加是相同的,当我必须对其中一个进行更改时,我必须将其复制粘贴到其他函数,这些函数显然不能移动到基本控制器。

这是一个可视化的演示代码:

usagedemo.php

require_once 'CtrlNotCommon.php';
require_once 'CtrlCommonFeatureWeb.php';
require_once 'CtrlCommonFeatureAdmin.php';

$ctrlNotCommon = new CtrlNotCommon();
$ctrlCommonFeatureWeb = new CtrlCommonFeatureWeb();
$ctrlCommonFeatureWeb->index();
$ctrlCommonFeatureAdmin = new CtrlCommonFeatureAdmin();
$ctrlCommonFeatureAdmin->index();

谢谢

【问题讨论】:

  • 什么重复?在哪里?这是不可能理解的,你甚至试图描述什么。我得到的只是你滥用继承权。
  • @teresko,我修改了我的问题以使其更清楚。如果还不清楚,请告诉我。谢谢。
  • 由于某种原因,今天我无法正确格式化问题中的代码,如果有人可以提供帮助,我们将不胜感激。谢谢。
  • 你能举例说明这些方法中的代码吗?只是说有重复是没有意义的。 CtrlBaseAdminCtrlBaseCMS 到底有什么区别?
  • 我们可以看看您所指的这 3 个 CTOR 吗?可能你可以完全避免一个 lvl 的继承。

标签: php oop design-patterns


【解决方案1】:
  1. 如果您想在多个独立应用程序之间共享代码,您可能可以使用基本控制器类创建自己的库,并使用composer 进行依赖管理。如果有相同的代码库,那就更容易了,因为在这种情况下,您可以将基类保留在项目中。
  2. 您可以使用基本控制器的抽象类来组织代码,并在其中保留共享方法(它们是相同的)。
  3. 另一种方法是使用特征,因此您可以创建特征,将所有要共享的方法放在那里,然后在控制器中使用该特征。

【讨论】:

    【解决方案2】:

    你可以:

    • 创建抽象类User并实现每个User控制器(UserAdmin/UserCms/UserWeb);

    • 在您将在所有应用程序中使用的核心文件夹中创建控制器的核心目录 - 最快且编码更少;

    主要思想是相同的:大多数 PHP 框架不依赖于繁重的 OOP,恕我直言,它应该如此。如果您自己实施一个,请给自己一个这样做的机会,并在将来避免头痛。

    采用第二个选项是一种丑陋的方式。用户乍一看可以有相同的方法,但是当你在另一个系统中使用时,所实现的表和一些业务规则会发生变化。这样做会放置很多开关和 ifs 来过滤当前实例想要什么/在哪里调用它。

    第一个选项是这样的:

    // Define things a user *has* to be able to do (has to implement)
    interface iUser {
        public function set();
        public function get();
        public function setTable();
    }
    
    // Define our default abstraction
    abstract class DefaultUser implements iUser {
        private $_username = false;
        private $_userid = false;
        protected $_table = false;
        public function get() {
            /* the default implementation */
            echo "defaultUser get";
        }
        public function set() {
            echo "defaultUser set";
        }
    }
    
    class UserAdmin extends DefaultUser {
        public function setTable($table) {
            $this->_table = $table;
        }
    
        public function set() {
            echo "UserAdmin's set() and also my parent's set()";
            parent::set();
        }
    
        public function get() {
            echo "UserAdmin's get() and also my parent's get()";
            parent::get();
        }
    }
    
    class UserCMS extends DefaultUser {
        public function setTable($table) {
            $this->_table = $table;
        }
    
        public function set() {
            echo "UserCMS's set() and also my parent's set()";
            parent::set();
        }
    
        public function get() {
            echo "UserCMS's get() and also my parent's get()";
            parent::get();
        }
    }
    

    PS:将类和接口分开到不同的文件中。

    【讨论】:

    • 谁对这个答案投了反对票,请您发表评论。在澄清已经是一个模糊的问题方面,它是徒劳的。假设您的比赛是有效的。
    • @Abstractioniseverything。我也很好奇,只是在等待改进我的答案,这很复杂,没有理由帮助解决这个问题。
    猜你喜欢
    • 2017-06-04
    • 2019-02-01
    • 2012-03-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    • 1970-01-01
    • 2015-01-05
    • 2012-09-02
    相关资源
    最近更新 更多