什么是与Singleton交互的最有效方式?

时间:2022-09-23 17:14:05

I've been working on my own little framework for a while for my own benefit, constantly going back over the code as I learn new stuff. As you might expect, I have a Registry object that's used by pretty much every other object.

为了自己的利益,我一直在为自己的小框架工作一段时间,在我学习新东西时不断回头看代码。正如您所料,我有一个几乎所有其他对象都使用的Registry对象。

At present, the most basic object (AFObject) is set up a little like this

目前,最基本的对象(AFObject)设置有点像这样

absract class AFObject {

    var $_registry;

    function __construct(){
        $this->_registry = AFRegistry::getInstance();
    }

}

So every object will now contain a local reference to the Registry. So if I have hundreds of objects instantiated at 1 time, that's hundreds of references to the singleton. But would it be more or less efficient to always refer to the Registry directly like this...

因此,每个对象现在都包含对注册表的本地引用。因此,如果我有一次实例化数百个对象,那就是数百个对单例的引用。但总是像这样直接引用注册表会有多少或多少效率......

class AFRouter extends AFObject {

    function someMethod( $bar ){
        AFRegistry::$foo = $bar;
    }

}

3 个解决方案

#1


In my opinion, "registry" type of classes kind of smells.

在我看来,“注册表”类的类气味。

Since you mentioned you were doing this for learning and getting better, have you ever considered completely eradicating your registry class and taking another approach? Perhaps pushing required data to class constructors instead of pulling it from the inside of the class?

既然你提到你这样做是为了学习和变得更好,你有没有考虑完全根除你的注册表类并采取另一种方法?也许将所需的数据推送到类构造函数而不是从类的内部拉出来?

I'd leave out option 1 (abstract base class), because then all your classes becomes dependent on some other classes...

我会省略选项1(抽象基类),因为那时你的所有类都依赖于其他一些类......

Using a static class like Yngve Sneen mentioned would be the best approach in my opinion if you do wish to keep a registry setup.

如果您希望保留注册表设置,那么在我看来,使用像Yngve Sneen这样的静态类是最好的方法。

Something like: registry::set('var1', $var1); $var1 = registry::get('var1');

类似于:registry :: set('var1',$ var1); $ var1 = registry :: get('var1');

#2


Consider this:

class AFRouter extends AFObject {
  function someMethod($bar) {
    global $af_registry;
    $af_registry->setFoo($bar);
  }
}

or even:

class AFRouter extends AFObject {
  function someMethod($bar) {
    af_registry_set('foo', $bar);
  }
}

Bar the syntax, there is essentially no difference between this and your current solution.

除了语法之外,这与您当前的解决方案之间基本没有区别。

Yes, that means that your registry is essentially a global variable. And yes, there are problems with global variables. A better option would be to pass in the dependencies.

是的,这意味着您的注册表本质上是一个全局变量。是的,全局变量存在问题。更好的选择是传递依赖项。

#3


I don't think you should think about efficiency in this case (since 100 references really isn't a problem, and is a bit premature optimization). But consider what is most elegant in your code. Also, consider if you need a singleton (could it be implemented as a static class?). I would maybe choose to use your second case, since that makes your code a bit more obvious (at least I think so).

在这种情况下,我认为你不应该考虑效率(因为100个引用确实不是问题,并且有点过早优化)。但请考虑代码中最优雅的内容。另外,考虑一下你是否需要一个单例(它可以实现为静态类吗?)。我可能会选择使用你的第二种情况,因为这会使你的代码更加明显(至少我认为是这样)。

In that case it would be

在那种情况下,它会

class AFRouter extends AFObject {

    function someMethod( $bar ){
        AFRegistry::getInstance()->$foo = $bar;
    }

}

Or if you encapsulate your property:

或者,如果您封装了您的财产:

class AFRouter extends AFObject {

    function someMethod( $bar ){
        AFRegistry::getInstance()->setFoo($bar);
    }

}

#1


In my opinion, "registry" type of classes kind of smells.

在我看来,“注册表”类的类气味。

Since you mentioned you were doing this for learning and getting better, have you ever considered completely eradicating your registry class and taking another approach? Perhaps pushing required data to class constructors instead of pulling it from the inside of the class?

既然你提到你这样做是为了学习和变得更好,你有没有考虑完全根除你的注册表类并采取另一种方法?也许将所需的数据推送到类构造函数而不是从类的内部拉出来?

I'd leave out option 1 (abstract base class), because then all your classes becomes dependent on some other classes...

我会省略选项1(抽象基类),因为那时你的所有类都依赖于其他一些类......

Using a static class like Yngve Sneen mentioned would be the best approach in my opinion if you do wish to keep a registry setup.

如果您希望保留注册表设置,那么在我看来,使用像Yngve Sneen这样的静态类是最好的方法。

Something like: registry::set('var1', $var1); $var1 = registry::get('var1');

类似于:registry :: set('var1',$ var1); $ var1 = registry :: get('var1');

#2


Consider this:

class AFRouter extends AFObject {
  function someMethod($bar) {
    global $af_registry;
    $af_registry->setFoo($bar);
  }
}

or even:

class AFRouter extends AFObject {
  function someMethod($bar) {
    af_registry_set('foo', $bar);
  }
}

Bar the syntax, there is essentially no difference between this and your current solution.

除了语法之外,这与您当前的解决方案之间基本没有区别。

Yes, that means that your registry is essentially a global variable. And yes, there are problems with global variables. A better option would be to pass in the dependencies.

是的,这意味着您的注册表本质上是一个全局变量。是的,全局变量存在问题。更好的选择是传递依赖项。

#3


I don't think you should think about efficiency in this case (since 100 references really isn't a problem, and is a bit premature optimization). But consider what is most elegant in your code. Also, consider if you need a singleton (could it be implemented as a static class?). I would maybe choose to use your second case, since that makes your code a bit more obvious (at least I think so).

在这种情况下,我认为你不应该考虑效率(因为100个引用确实不是问题,并且有点过早优化)。但请考虑代码中最优雅的内容。另外,考虑一下你是否需要一个单例(它可以实现为静态类吗?)。我可能会选择使用你的第二种情况,因为这会使你的代码更加明显(至少我认为是这样)。

In that case it would be

在那种情况下,它会

class AFRouter extends AFObject {

    function someMethod( $bar ){
        AFRegistry::getInstance()->$foo = $bar;
    }

}

Or if you encapsulate your property:

或者,如果您封装了您的财产:

class AFRouter extends AFObject {

    function someMethod( $bar ){
        AFRegistry::getInstance()->setFoo($bar);
    }

}