工厂静态方法和私有构造函数

I have an class Foo and a class Bar and I want to utilize Bar's static methods to get a singleton instance of Foo, (similar to the way BitmapFactory.create() returns a Bitmap instance), BUT Foo should not be instanced using new Foo(), how do I get that?

class Foo {
    $private Foo() {} // ??
}

class Bar {
    private static $foo = null;
    static function getFooInstance() {
         if(Bar::$foo == null) $foo = new Foo();               
         return Bar::$foo;
    }
} 



$foo = Bar::getFooInstance();

The what you want to do is make Foo a singleton and make Bar assign to bar by Foo::getInstance(); For example:

class Foo {
    private static $instance;
    private function __construct(){}
    public static function getInstance(){
        if (!isset(self::$instance)){
            self::$instance = new Foo();
        }
        return self::$instance;
    }
    public function __clone(){
        throw new Exception("Cannot Clone Singletons... bad programmer");
    }
}

class Bar {
    static function getFooInstance() {
         return Foo::getInstance();
    }
} 

There is no need to replay the singleton pattern within Bar as Foo already polices it's own instantiation.

There is really no need to use a singleton pattern here. The singleton is a bad pattern and should be avoided.

The best solution is: Make a static factory method in Bar that guarantees that there will be only one Foo created. You already did that.

And for Foo: Simply do not instantiate it on it's own in your productive code. But you really want to instantiate several copys of Foo in your tests! Because of that you cannot make the constructor of Foo non-public.

Objects that usually are only created once should play an important part in your application. They will most likely be created once at the start and then used for several things. Create a dedicated factory class for this (or maybe one per topic: for models, for database and for templates). Make it a habit to only use these factories to create objects.

Or even better, add this to your Dependency Injection framework as a configuration. Usage when getting the objects is basically the same.