Domanda

Let's say I want to have a set of objects, each of which should have its own unique ID. Nothing fancy is needed, just a letter denoting which type of object it is, and a number denoting how many objects of these have been created. So for instance, a0, a1, b0, c0, c1, c2, c3, and so on.

Rather than setting global variables to keep track of how many of each object already exist, I want to do so with a class. Like so:

class uniqueIDGenerator
{
  private $numberAObjs;
  private $numberBObjs;
  private $numberCObjs;

  public function generateID ($type) {
    if($type === "A") {
      return 'a' . (int) $this->$numberAObjs++;
    } else if($type === "B") {
      return 'b' . (int) $this->$numberBObjs++;
    } else if($type === "C") {
        return 'c' . (int) $this->$numberCObjs++;
    }
  }
}

class obj
{
  private $id;

  function __construct($type) {
    $this->id = uniqueIDGenerator::generateID($type);
  }
}

The problem with this is that if uniqueIDGenerator is uninstantiated, its generateID function will always return the same values for each type (e.g. a0, b0, c0, etc.) because its private variables haven't actually been created in memory. At the same time, making it a property of obj won't work because then each time an obj is created, it will have its own instance of uniqueIDGenerator, so that will also always return a0, b0, c0, (assuming it's only called once in that object's methods) and so on.

The only option seems to be to make uniqueIDGenerator its own global instance so obj's constructor can reference it, but that seems poor coding practice. Is there any good, OOP way to do this that keeps all the objects separate and organized?

È stato utile?

Soluzione

First you can modify object constructor:

class obj
{
  private $id;

  function __construct($type, $id) {
    $this->id = $id;
  }
}

...

$id_generator = new uniqueIDGenerator(); // instanciation of the generator

$obj1 = new obj(type, $id_generator->generateID($type));
$obj2 = new obj(type, $id_generator->generateID($type));
$obj3 = new obj(type, $id_generator->generateID($type));
...

In my projects, I would create a class named ObjectFactory:

    class ObjectFactory {
       private $id_generator;

       public function __construct($id_generator) {
          $this->id_generator = $id_generator;
       }

       public function create_object($type) {
          return new obj($this->id_generator->generateID($type));
       }
    }

...

$id_generator = new uniqueIDGenerator(); // instanciation of the generator
$obj_factory = new ObjectFactory($id_generator); 

$obj1 = obj_factory->create_object($type);
$obj2 = obj_factory->create_object($type);
$obj3 = obj_factory->create_object($type);

Finaly, to avoid the use of a global instance of this class, you can do a Singleton (adapted to your situation):

class uniqueIDGenerator
{
  private $numberAObjs;
  private $numberBObjs;
  private $numberCObjs;

  public static $instance = null;

  public function __construct() {
    $numberAObjs = 0;
    $numberBObjs = 0;
    $numberCObjs = 0;
  }

  public static function generateID($type) {
     if(!self::$instance)
        self::$instance = new uniqueIDGenerator();

     return self::$instance->generateID2($type);
  }

  private function generateID2 ($type) {
    if($type === "A") {
      return 'a' . (int) $this->numberAObjs++;
    } else if($type === "B") {
      return 'b' . (int) $this->numberBObjs++;
    } else if($type === "C") {
        return 'c' . (int) $this->numberCObjs++;
    }
  }
}

uniqueIDGenerator::generateID("A");
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top