富贵资源网 Design By www.hznty.com

工作单元

这个模式涉及到了领域模型、数据映射器和标识映射,这里就统一进行整理和回顾了。

$venue = new \woo\domain\Venue(null,"The Green Tree");

\woo\domain\ObjectWatcher::instance()->performOperations();

现在以上面的二行客户端代码为切入点大概的叙述一下这个模式是怎么工作的。

第一句在使用领域模型对象创建一个对象的时候,它就调用了标识映射ObjectWatcher类

将自己标记为一个需要新增的对象。第二句的performOperations方法将保存在标识映射器的属性$new中的对象

插入到了数据库中。注意它内部调用的$obj->finder()方法是领域模式中通过HelperFactory工厂类生成一个相对应的数据映射器类并return过来。

HelperFactory这个类下面没有具体实现(原文也没有实现),其实就是根据参数传入的类的类型使用条件分支创建对应的数据映射器。

下面直接看代码和注释进行理解。

namespace woo\domain;

//标识映射
class ObjectWatcher{
  
  private $all = array();        //存放对象的小仓库
  private $dirty = array();      //存放需要在数据库中修改的对象
  private $new = array();        //存放需要在数据库中新增的对象
  private $delete = array();      //存放需要在数据库中删除的对象
  private static $instance;      //单例
  
  
  private function __construct (){}
  
  static function instance(){
    if(!self::$instance){
      self::$instance = new ObjectWatcher();
    }
    return self::$instance;
  }
  
  //获取一个唯一的标识,这里采用了领域类类名+ID的方式创建一个唯一标识,避免多个数据库表调用这个类时出现ID重复的问题
  function globalKey(DomainObject $obj){
    $key = get_class($obj) . "." . $obj->getId();
    return $key;
  }
  
  //添加对象
  static function add(DomainObject $obj){
    $inst = self::instance();
    $inst->all[$inst->globalKey($obj)] = $obj;
  }
  
  //获取对象
  static function exists($classname,$id){
    $inst = self::instance();
    $key = "$classname.$id";
    if(isset($inst->all[$key]){
      return $inst->all[$key];
    }
    return null;
  }
  
  //标记为需要删除的对象
  static function addDelete(DomainObject $obj){
    $self = self::instance();
    $self->delete[$self->globalKey($obj)] = $obj;
  }
  
  //标记为需要修改的对象
  static function addDirty(DomainObject $obj){
    $inst = self::instance();
    if(!in_array($obj,$inst->new,true)){
      $inst->dirty[$inst->globalKey($obj)] = $obj;
    }
  }
  
  //标记为需要新增的对象
  static function addNew(DomainObject $obj){
    $inst = self::instance();
    $inst->new[] = $obj;
  }
  
  //标记为干净的对象
  static function addClean(DomainObject $obj){
    $self = self::instance();
    unset($self->delete[$self->globalKey($obj)]);
    unset($self->dirty[$self->globalKey($obj)]);
    $self->new = array_filter($self->new,function($a) use($obj) {return !($a === $obj);});
  }
    
  //将上述需要增删改的对象与数据库交互进行处理  
  function performOperations(){
    foreach($this->dirty as $key=>$obj){
      $obj->finder()->update($obj);    //$obj->finder()获取一个数据映射器
    }
    foreach($this->new as $key=>$obj){
      $obj->finder()->insert($obj);
    }
    $this->dirty = array();
    $this->new = array();
  }
}


//领域模型
abstract class DomainObject{      //抽象基类
  
  private $id = -1;
  
  function __construct ($id=null){
    if(is_null($id)){
      $this->markNew();      //初始化时即被标记为需要新增的对象了
    } else {
      $this->id = $id;
    }  
  }
  
  //调用了标识映射的标记对象的方法
  function markNew(){
    ObjectWatcher::addNew($this);
  }
  
  function markDeleted(){
    ObjectWatcher::addDelete($this);
  }
  
  function markDirty(){
    ObjectWatcher::addDirty($this);
  }
  
  function markClean(){
    ObjectWatcher::addClean($this);
  }
  
  function setId($id){
    $this->id = $id;
  }
  
  function getId(){
    return $this->id;
  }
  
  
  function finder(){
    return self::getFinder(get_class($this));
  }
  
  //通过工厂类来实例化一个特定类型的数据映射器对象,例如VenueMapper
  //这个对象将被标识映射器中的performOperations方法调用用于与数据库交互进行增删改的操作
  static function getFinder($type){
    return HelperFactory::getFinder($type);
  }
  
}


class Venue extends DomainObject {
  private $name;
  private $spaces;
  
  function __construct ($id = null,$name=null){
    $this->name= $name;
    $this->spaces = self::getCollection('\\woo\\domain\\space'); 
    parent::__construct($id);
  }
  
  function setSpaces(SpaceCollection $spaces){
    $this->spaces = $spaces;
    $this->markDirty();            //标记为需要修改的对象
  }
  
  function addSpace(Space $space){
    $this->spaces->add($space);
    $space->setVenue($this);
    $this->markDirty();            //标记为需要修改的对象
  }
  
  function setName($name_s){
    $this->name = $name_s;
    $this->markDirty();            //标记为需要修改的对象
  }
  
  function getName(){
    return $this->name;
  }
}


//领域模型
class Space extends DomainObject{
  //.........
  function setName($name_s){
    $this->name = $name_s;
    $this->markDirty();
  }
  
  function setVenue(Venue $venue){
    $this->venue = $venue;
    $this->markDirty();
  }
}


//数据映射器
abstract class Mapper{
  
  abstract static $PDO;    //操作数据库的pdo对象
  function __construct (){
    if(!isset(self::$PDO){
      $dsn = \woo\base\ApplicationRegistry::getDSN();
      if(is_null($dsn)){
        throw new \woo\base\AppException("no dns");
      }
      self::$PDO = new \PDO($dsn);
      self::$PDO->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION);
    }
  }
  
  //获取标记的对象
  private function getFroMap($id){
    return \woo\domain\ObjectWatcher::exists($this->targetClass(),$id);
  }
  
  
  //新增标记的对象
  private function addToMap(\woo\domain\DomainObject $obj){//////
    return \woo\domain\ObjectWatcher::add($obj);
  }
  
  
  //将数据库数据映射为对象
  function createObject($array){
    $old = $this->getFromMap($array['id']);
    if($old){return $old;}
    $obj = $this->doCreateObject($array);
    $this->addToMap($obj);
    $obj->markClean();
    return $obj;
  }

  
  function find($id){                //通过ID从数据库中获取一条数据并创建为对象  
    $old = $this->getFromMap($id);        
    if($old){return $old}            
    
    $this->selectStmt()->execute(array($id));
    $array= $this->selectStmt()->fetch();
    $this->selectStmt()->closeCursor();
    if(!is_array($array)){
      return null;
    }
    if(!isset($array['id'])){
      return null;
    }
    $object = $this->createObject($array);
    $this->addToMap($object);          
    return $object;  
  }
  
  
  function insert(\woo\domain\DomainObject $obj){      //将对象数据插入数据库
    $this->doInsert($obj);
    $this->addToMap($obj);            
  }
  
  //需要在子类中实现的各个抽象方法
  abstract function targetClass();                    //获取类的类型
  abstract function update(\woo\domain\DomainObject $objet);        //修改操作
  protected abstract function doCreateObject(array $array);        //创建对象
  protected abstract function selectStmt();                //查询操作
  protected abstract function doInsert(\woo\domain\DomainObject $object);  //插入操作
  
}

class VenueMapper extends Mapper {
  function __construct (){    
    parent::__construct();  
    //预处理对象
    $this->selectStmt = self::$PDO->prepare("select * from venue where id=");
    $this->updateStmt = self::$PDO->prepare("update venue set name=");
    $this->insertStmt = self::$PDO->prepare("insert into venue (name) values(");
  }
  
  protected function getCollection(array $raw){    //将Space数组转换成对象集合
    return new SpaceCollection($raw,$this);        
  }
  
  protected function doCreateObject (array $array){  //创建对象
    $obj = new \woo\domain\Venue($array['id']);
    $obj->setname($array['name']);
    return $obj;
  }
  
  protected function doInsert(\woo\domain\DomainObject $object){ //将对象插入数据库
    print 'inserting';
    debug_print_backtrace();
    $values = array($object->getName());
    $this->insertStmt->execute($values);
    $id = self::$PDO->lastInsertId();
    $object->setId($id);
  }
  
  function update(\woo\domain\DomainObject $object){    //修改数据库数据
    print "updation\n";
    $values = array($object->getName(),$object->getId(),$object->getId());
    $this->updateStmt->execute($values);
  }
  
  function selectStmt(){          //返回一个预处理对象
    return $this->selectStmt;
  }
  
}


//客户端
$venue = new \woo\domain\Venue(null,"The Green Tree");        //在初始化时就被标记为新增对象了
$venue->addSpace(new \woo\domain\Space(null,"The Space Upstairs"));  //这二行addSpace方法因为venue已经被标记新增所以不会再标记为修改对象,但是space在初始化的时候会被标记为新增对象
$venue->addSpace(new \woo\domain\Space(null,"The Bar Stage"));      
\woo\domain\ObjectWatcher::instance()->performOperations();      //与数据库交互新增一条Venue数据,以及二条space数据

以上这篇PHP面向对象之工作单元(实例讲解)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

富贵资源网 Design By www.hznty.com
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
富贵资源网 Design By www.hznty.com

稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!

昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。

这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。

而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?