使用对象作为键的多维地图
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用对象作为键的多维地图相关的知识,希望对你有一定的参考价值。
我有一组对象(MainObject
),它们由两个对象(SubObject1
,SubObject2
)和一个字符串(theString
)唯一定义。我通过返回基于两个子对象和字符串的现有对象来检索集合中的MainObject
,否则创建一个新对象,将其添加到集合中,然后返回该对象。
以下伪代码在make believe world中演示了这一点,标准数组可以使用对象作为键。
class SubObject1{}
class SubObject2{}
class MainObject{
private $subObject1, $subObject2, $theString;
public function __construct(SubObject1 $subObject1, SubObject2 $subObject2, string $theString):MainObject {
$this->subObject1=$subObject1;
$this->subObject2=$subObject2;
$this->theString=$theString;
}
}
class ObjectCollection
{
private $map=[];
public function getObject(SubObject1 $subObject1, SubObject2 $subObject2, string $theString):MainObject {
if(isset($this->map[$subObject1][$subObject2][$theString])) {
$mainObject=$this->map[$subObject1][$subObject2][$theString];
}
else {
$mainObject=new MainObject($subObject1, $subObject2, $theString);
$this->map[$subObject1][$subObject2][$theString]=$mainObject;
}
return $mainObject;
}
}
$objectCollection=new ObjectCollection();
$subObject1_1=new SubObject1();
$subObject1_2=new SubObject1();
$subObject2_1=new SubObject2();
$subObject2_1=new SubObject2();
$o=$objectCollection->getObject($subObject1_1, $subObject2_1, 'hello'); //returns a new object
$o=$objectCollection->getObject($subObject1_2, $subObject2_1, 'hello'); //returns a new object
$o=$objectCollection->getObject($subObject1_1, $subObject2_1, 'goodby'); //returns a new object
$o=$objectCollection->getObject($subObject1_1, $subObject2_1, 'hello'); //returns existing object
如何最好地实施?
一种可能性类似于以下未经测试的代码,但是,如果有更清洁的解决方案,它有点冗长并且感兴趣。
public function getObject(SubObject1 $subObject1, SubObject2 $subObject2, string $theString):MainObject {
if(isset($this->map[$theString])) {
if($this->map[$theString]->contains($subObject1)) {
$subObject1Storage=$this->map[$theString][$subObject1];
if($subObject1Storage->contains($subObject2)) {
$mainObject=$subObject1Storage[$subObject2];
}
else {
$mainObject=new MainObject($subObject1, $subObject2, $theString);
$subObject1Storage[$subObject2]=$mainObject;
}
}
else {
$subObject1Storage = new SplObjectStorage();
$this->map[$theString][$subObject1]=$subObject1Storage;
$mainObject=new MainObject($subObject1, $subObject2, $theString);
$subObject1Storage[$subObject2]=$mainObject;
}
}
else {
$this->map[$theString] = new SplObjectStorage();
$subObject1Storage = new SplObjectStorage();
$this->map[$theString][$subObject1]=$subObject1Storage;
$mainObject=new MainObject($subObject1, $subObject2, $theString);
$subObject1Storage[$subObject2]=$mainObject;
}
return $mainObject;
}
答案
我想到的逻辑如下:
工厂(如果对象太多,则为抽象工厂)将负责创建对象本身。
容器将使用工厂创建的对象映射唯一标识符。并且可以根据这些标识符检索对象。
这是最容易的部分,自定义部分应该更容易,你可以添加自己的方法,用别名等做你需要的任何魔法。
namespace Example;
/**
* Class ObjectFactory
*
* @package Example
*/
class ObjectFactory {
/**
* This is obviosuly not ideal but it can work
* with a limited amount of objects. Otherwise use an
* abstract factory and let each instance take care of a few
* related objects
*
* @param string $objectAlias
*
* @throws Exception
*/
public function make(string $objectAlias) {
switch($objectAlias) {
case 'object_unique_id_1':
try{
$instance = new $objectAlias;
}catch (Exception $exception) {
// log or whatever and rethrow
throw new Exception("Invalid class? maybe, I dunno");
}
// return $instance
// etc
}
}
}
你也可以在这里使用Reflection以递归方式获取对象的参数,并根据构造中的参数转储当前对象中对象的新实例,从而创建自己的小DI容器。
但是,如果你想保持你的理智使用像Pimple。
容器:
<?php
namespace Example;
/**
* Class Container
*
* @package Example
*/
class Container {
/**
* @var array
*/
private $map = [];
/**
* @param $objectAlias
* @param $objectInstance
*
* @throws Exception
*/
public function set($objectAlias, $objectInstance) {
// You can use a try catch here, I chose not to
if(isset($this->map[$objectAlias])) {
throw new Exception("Already exists");
}
$this->map[$objectAlias] = $objectInstance;
}
/**
* @param $objectAlias
*
* @return bool|mixed
*/
public function get($objectAlias) {
if(isset($this->map[$objectAlias])) {
return $this->map[$objectAlias];
}
return false;
}
}
具有自己方法的特定容器
<?php
namespace Example;
/**
* Class ContainerHashMapThingy
*
* @package Example
*/
class ContainerHashMapThingy extends Container {
// Your methods go here
}
一个示例对象:
<?php
namespace Example;
/**
* Class ExampleObject1
*
* @package Example
*/
class ExampleObject1 {
/**
* @return string
*/
public function alias() {
// This is just for example sake
// You can just as well have a config, another class to map them or not map them at all
return 'example_object_1';
}
}
还有一个实际的例子
<?php
$factory = new ExampleObjectFactory();
$container = new ExampleContainer();
$objectOne = $factory->make('example_object_1');
$container->set('first_object', $objectOne);
这里的想法是给你一个容器+工厂的清洁石板。
如果扩展容器,您可以实现自己的方法,从map
数组中删除东西,甚至重写set
方法以满足您自己的需要。
虽然这不是一个完整的答案,但很难给出一个,因为正如我所说,你的需求可能会有所不同。
我希望这能让你走上正轨。
以上是关于使用对象作为键的多维地图的主要内容,如果未能解决你的问题,请参考以下文章