工厂方法:防止类直接实例化

时间:2016-05-04 18:30:24

标签: php oop design-patterns factory factory-pattern

我有一个Factory Method来实例化一个类。有没有办法防止这个类直接实例化?

我看到的唯一选择是使用传递给__construct()的参数,但这不是我正在寻找的东西。

另一方面,将__construct()设为私有是理想的,但我不希望MyClass在没有实际需要的情况下延长Factory

你们有什么想法?

工厂方法:

class Factory
{
    public static function instance()
    {
        return new MyClass(true);
    }
}

MyClass的:

class MyClass
{
    public function __construct($isFactory = false)
    {
        if (!$isFactory) {
            throw new Exception('Use Factory::instance() to create an object');
        }
    }
}

3 个答案:

答案 0 :(得分:2)

有一些黑客可以做到这一点:

  • 滥用继承以使用protected构造函数
  • 将工厂方法放在类中,以便它可以调用私有构造函数,这实际上不是一个hack。但那么为什么不首先使用构造函数呢?
  • 使用反射访问私有构造函数

我没有宣传任何相关内容。我个人所做的是使用@internal之类的东西来记录API,并在合同之后将其留给客户。

答案 1 :(得分:1)

从本质上讲,您的代码应该是这样的:

工厂

    <?php
    class Factory {

        public static function instance(){
            return new MyClass(true); //HERE YOU ARE INSTANTIATING
        }
    }

通过工厂实现的课程

     <?php
    //NOT MyClass() <--- YOU ARE DEFINING.... NOT INSTANTIATING...
    class MyClass {

        public function __construct($isFactory = false) {
            if (!$isFactory) {
                throw new Exception('Use Factory::instance() to create an object');
            }
        }

        //...MORE METHODS
    }

你能尝试一下吗?

    <?php
        class Factory
        {
            private static $FACTORY_GUARANTOR;      //ONLY SET DURING INSTANTIATION
            public static function instance($type) {
                if (class_exists($type)) {
                    self::$FACTORY_GUARANTOR = 1;
                    $instance = new $type();
                    self::$FACTORY_GUARANTOR = null;
                    return $instance;
                }
                else {
                    throw new Exception("Class not found...");
                }
            }

            //YOU CAN GET $FACTORYGUARANTOR EXTERNALLY BUT NEVER SET IT;
            public static function getGuarantor(){
                return self::$FACTORY_GUARANTOR;
            }
        }



        class MyClass {
            protected $property1;
            protected $property3;
            protected $property2;

            public function __construct() {
                // IF SOMEONE TRIES TO INSTANTIATE THE CLASS OUTSIDE OF THE FACTORY... BLOW A WHISTLE
                if(!Factory::getGuarantor()){
                    throw new Exception('Use Factory::instance() to create an object');
                }
                // IF THE PROGRAM MADE IT TO THIS POINT;
                // JUST INSTANTIATE THE CLASS BECAUSE MOST LIKELY IT IS COMING FROM THE FACTORY
                var_dump($this); // A LITTLE CONFIRMATION....
            }

            //...MORE METHODS
        }

        // TRY IT OUT:
        /*INSTANCE A: RIGHT*/   $theClass   = Factory::instance("MyClass"); //INSTANTIATES THE CLASS
        /*INSTANCE B: WRONG*/   $theClass   = new MyClass();                //THROWS AN EXCEPTION

答案 2 :(得分:0)

最简单的方法是将基类定义为abstractabstract类不能直接实例化,因此您必须在继承的类中重新定义其抽象成员:

abstract class Factory
{
    abstract public function foo();
}

class InheritedClass extends Factory
{
    public function foo()
    {
        // Do something
    }
}

// $obj1 = new Factory(); // Will produce an error
$obj1 = new InheritedClass(); // Will be executed successfully

您可以在PHP: Class Abstraction - Manualabstract类中阅读更多内容。

相关问题