在架构设计咨询(Advice on framework design)

2019-10-18 13:02发布

我目前正在构建某种小型框架的一个项目,并拿出这个解决方案。 我已经尝试了很多人,但是这在我看来十分便利(代码缩短了简单):

# Basically it's just a Registry pattern    
    class Repository {
        private static $objects = array();

        public function loadObject($alias, $object) {
            self :: $objects[$alias] = $object;
            return true;
        }

        public function __get($name) {
            if ($this->objectExists($name)) {
                return self::$objects[$name];
            } else {
                return false;
            }
        }
    }

    class Database extends Repository {
        /* database class */
    }

    class Session extends Repository {
        public function some_func($key, $value) {
            /* i can access database object using $this in any class that extends Repository */
            $this -> database -> exec (/* sql */);
        }
    }

    /* =================== */

    # Load core objects
    $R = new Repository :: getInstance();
    $R -> loadObject ('config', new Config());
    $R -> loadObject ('database', new Database());
    $R -> loadObject ('session', new Session());

    /* =================== */

你能看到使用这种方法的任何问题或弊端? 对我来说,我看也许我多一点的内存消耗,因为每个隔壁班拥有库越来越多的对象。 之前,我有一个设计,其中每个类是独立的,但无论如何,他们都需要数据库,会话,配置等,不,我不得不宣布他们在任何类。 只是想指出,我计划这样的设计只为核心对象,而不是具体的类。

Answer 1:

“因为每个下一堂课持有库越来越多的对象” - 我完全不明白你什么意思,我觉得作为对象是静态的,只有一个副本。

我想你可以用一点点不同的方法来避免缺点,结合Singleton模式。

class Repository
{
  private static $instance;
  private $objects = array();
  private static getInstance()
  {
    if (!Repository::$instance)
      !Repository::$instance = new Repository();
    return !Repository::$instance();
  }

  public static function loadObject($alias, $object)
  {
    Repository::getInstance()->objects[$alias] = $object;
    return true;
  }

  public static function get($name)
  {
    $repository = Repository::getInstance();
    if (isset($repository->objects[$name]
      return $repository->objects[$name];
    else
      return false;
}

那么你会在你的子类使用此:

Repository::get('config');

并在引导

Repository::loadObject('config', new Config());
Repository::loadObject('database', new Database());

等等



Answer 2:

不要延长Repository

  • 数据库是不是一个仓库,一个仓库有一个数据库
  • 你的数据库/会话/配置是不相关的,不应该。 里氏替换原则 :

[...]如果S是T的子类型,则在节目类型T的对象可以与S型的对象替换,而不改变任何程序(例如,正确性)的期望的性质。

编辑:要回答这个答复后续问题。

这种技术被称为依赖注入。 会话例如:

class Session {
    // notice the clean API since no methods are carried along from a possibly huge base class
    public function __construct(ISessionStorage $storage) {
        $this->_storage = $storage;
    }
    public function set($key, $value) {
        $this->_storage->set($key, $value);
    }
}

interface ISessionStorage {
    public function set($key, $value);
}

class DatabaseSessionStorage implements ISessionStorage {
    public function __construct(Db $db) {
        $this->_db = $db
    }
    public function set($key, $value) {
        $this->_db->query("insert....");
    }
}

class CookieSessionStorage implements ISessionStorage {
    public function set($key, $value) {
        $_SESSION[$key] = $value;
    }
}

// example where it's easy to track down which object went where (no strings used to identify objects)
$session = new Session(new DatabaseSessionStorage(new Db()));
$session->set('user', 12512);
// or, if you'd prefer the factory pattern. Note that this would require some modification to Session
$session = Session::factory('database');
$session->set('user', 12512);

当然,你可以存储在配置文件中的硬编码的连接设置。 这不仅意味着其他文件需要获得配置类的保留状态,而通过他们的父母一起去。 例如:

class Database {
    // The same pattern could be used as with the sessions to provide multiple database backends (mysql, mssql etc) through this "public" Database class
    public function __construct(Config $config) {
        $this->_config = $config;
        $this->_connect();
    }
    private function _connect() {
        $this->_config->getDatabaseCredentials();
        // do something, for example mysql_connect() and mysql_select_db()
    }
}

如果您希望保留的配置信息出来的PHP文件(编辑更容易/读取),看到了Zend_Config -班访问不同的存储设备,包括比较常见的例子:INI,PHP数组,XML。 (我只提Zend_Config的,因为我用它和我满意, parse_ini_file会做的一样好。)

一个好的和希望很容易看懂: Fabience Potencier -什么是依赖注入?


编辑#2:

另请参阅幻灯片: 马修纬二路O'Phinney -架构设计你的模型



Answer 3:

我认为这是一个坏榜样。 保持物体,如在内部数组配置,数据库和会话是不适合的。 这些对象应该是在你的基类的明确(可能是静态的)性能,应由确切名称进行访问。 纯粹主义者可能会说,它可以访问数组,这也是慢于直接访问属性:-))我想实现这些目标为单身,也许把他们藏在类似的应用类。 我想重写__get()是很好的为具有动态特性,或当你想阻止访问不存在的属性(只是抛出异常)的对象。 这也有助于通过PHP(我恨他们:-))当任何属性未定义(副作用)反对通知书上涨,但应通知被杀死明确,因为他们(小,但...)刚刚BUGS! 保持在属于特定对象(具有几十性质的)内部阵列性能。 我在映射到数据库表中的记录类大量使用这一解决方案。

问候。



文章来源: Advice on framework design