注册表模式和已注册对象的延迟实例化 [英] Registry pattern and lazy instantiation of registered objects

查看:99
本文介绍了注册表模式和已注册对象的延迟实例化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有注册表模式...

Let's imagine that we have Registry pattern...

<?php

class Registry
{

private static $objects     = array();
private static $instance    = null;

public static function getInstance() {
    if (self::$instance == null) {
        self::$instance = new Registry();
    }
    return self::$instance;
}

protected function _get($key) {
    return ($this->objects[$key]) ? $this->objects[$key] : null;
}

protected function _set($key, $val) {
    $this->objects[$key] = $val;
}

public static function get($key) {
    return self::getInstance()->_get($key);
}

public static function set($key, $object) {
    return self::getInstance()->_set($key, $object);
}

}
?>

使用此实现非常容易...

Using this realization is really easy...

<?
Registry::set('db', $db_client);
Registry::set('redis', $redis_client);

//Using registered objects is really easy
Registry::get('db')->query("...");
Registry::get('redis')->get("...");
?>

但是正如您所看到的,即使我们不需要实例,我们也将它们添加到注册表中(是的,这全都与性能有关). 因此,问题是...如何修改注册表模式以能够进行延迟实例化?

But as you can see, we're adding instances into registry even if we don't need them (yes, it's all about performance). So, the question is... How to modify Registry pattern to be able to do lazy instantiation?

这就是我想要的...

Here is what I'm looking for...

<?
class Registry
{

private static $objects     = array();
private static $instance    = null;

public static function getInstance() {
    if (self::$instance == null) {
        self::$instance = new Registry();
    }
    return self::$instance;
}

protected function _db() {
    if (!$this->objects['db']) {
        $this->objects['db'] = new DatabaseAdapter(DB_HOST, DB_NAME, DB_USER, DB_PASSWORD);
    }
    return $this->objects['db'];
}

protected function _redis() {
    if (!$this->objects['redis']) {
        $this->objects['redis'] = new Redis(REDIS_HOST, REDIS_DB, REDIS_USER, REDIS_PASSWORD);
    }
    return $this->objects['redis'];
}

public static function db() {
    return self::getInstance()->_db();
}

public static function redis() {
    return self::getInstance()->_redis();
}

}
?>

如您所见,将仅在我们请求时创建DatabaseAdapter()Redis().一切似乎都可以,但是您可以看到它不是一个独立的类,因为_db()_redis()方法包含连接常量等. 如何避免呢?如何在注册表类中定义注册表方法以将其中的Registy类和对象分开?

As you can see, DatabaseAdapter() or Redis() will be created only in we'll request them. Everything seems to be ok, but as you can see it's not a standalone class because _db(), _redis() methods contains connection constants etc. How to avoid it? How can I define registry method within registry class to separate Registy class and objects inside it?

我真的很抱歉我的英语,但希望对您来说很清楚.

I'm really sorry about my English, but I hope it is clear for you.

谢谢.

PS:上面的所有代码都写了1分钟.

推荐答案

如果使用全局常量,则始终会依赖于全局范围.不管在哪里.同样,即使您不使用常量,您仍然对注册表中的Database类有依赖性.如果要消除这些依赖关系,可以在要创建的类上使用Factory方法:

If you use global constants you will always have a dependency on the global scope. It doesnt matter where it is. Also, even if you do not use constants, you still have the dependency on the Database class inside the Registry. If you want to dissolve those dependencies, you could use Factory methods on the to be created classes:

public function get($service)
{
    if( !this->_data[$service] ) {
        // requires PHP 5.2.3
        this->_data[$service] = call_user_func($service .'::create');
    }
    return this->_data[$service];
}

因此,如果执行get('DB'),则代码将尝试在要创建的类中调用静态的DB::create()方法.但是就像我说的那样,如果您使用全局常量进行配置,则只需将问题移到另一个类中即可.

So if you do get('DB'), the code would try to call the static DB::create() method inside the class you intend to create. But like I said, if you use global Constants for the configuration, you would just move the problem into another class.

您的db类可能如下所示:

class DB
{
    protected static $_config;
    public static setConfig(array $config)
    {
        self::_config = $config;
    }
    public static create()
    {
        return new self(
            self::config['host'],
            self::config['db'],
            self::config['user'],
            self::config['pass']);
    }
}

配置可以存储在外部配置文件中,您可以在引导过程中将其加载并设置为DB类,例如

The configuration can be stored inside an external configuration file, which you load and set to the DB class during bootstrap, e.g.

DB::setConfig(parse_ini_file('/path/to/db-config.ini'));

的缺点是,您必须在各处添加create()方法,并且所有类都必须能够存储自己的配置.您可以将这些责任集中到构建器模式中.但是,如果您这样做,那么您仍然可以实现 IoC容器的一半,因此请查看以下资源:

The disadvantage of this is, you have to add create() methods all over the place and all classes must be able to store their own configuration. You could centralize these responsibilities into a Builder pattern. But if you do this, you are half way to implementing an IoC Container anyways, so check out the following resources:

  • Fabien Potencier: What is Dependency Injection
  • Martin Fowler: Inversion of Control Containers and the Dependency Injection pattern
  • Design pattern – Inversion of control and Dependency injection

这篇关于注册表模式和已注册对象的延迟实例化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆