浅谈设计模式之原型模式

背景知识:

  1. 我们常说的设计模式其实是一种代码规范,遵从设计模式所编写的代码并不是最高效的,但是是可维护的。
  2. 设计模式主要有三类:创建型设计模式,结构型设计模式以及行为型设计模式。
  3. 设计模式遵循的几个原则:开闭原则,里氏代换原则,依赖倒转原则,单一职责原则,合成复用原则,接口隔离原则,最小知识原则。

本文主要讲述原型模式,原型模式和我们在上一篇中讲的单例模式相似,都是关于对象的。只是单例模式的对象只创建一次,之后所有的操作都是围绕这一个对象展开的。而原型模式的目的则是为了获得新的对象,通过克隆的方式减少不断实例化所带来的开销。

在附上原型模式的事例代码之前,我们先来聊聊php中的深浅拷贝:我们都知道将一个对象赋值给一个变量是引用赋值(浅拷贝),将一个普通值赋值给一个变量是传值赋值(深拷贝),具体的效果是这样子的:

//传值赋值
$a=1;
var_dump($a);   ---> 打印结果为1
$b=$a;
$b=2;
var_dump($a);   ---> 打印结果仍为1

//引用赋值
class Dog{
    public $name;
    public function __construct($name){
        $this->name=$name;
    }
}
$a=new Dog(1);
var_dump($a->name);   ---> 打印结果为1
$b=$a;
$b->name=2;
var_dump($a->name);   ---> 打印结果为2

从以上的结果中我们不难看出,对象之间的赋值默认是引用赋值(浅拷贝),PHP提供了一个clone函数,可以实现对象之间的传值赋值(深拷贝):

//传值赋值
class Dog{
    public $name;
    public function __construct($name){
        $this->name=$name;
    }
}
$a=new Dog(1);
var_dump($a->name);   ---> 打印结果为1
$b=clone $a;
$b->name=2;
var_dump($a->name);   ---> 打印结果变为1

但是clone函数有一个缺点就是原对象的普通属性可以传值赋值,但是原对象的对象属性仍然是引用赋值:

class Cat{
    public $name;
    public function __construct($name){
        $this->name=$name;
    }
}

class Dog{
    public $name;
    public $cat;
    public function __construct($name){
        $this->name=$name;
        $this->cat=new Cat('cat');
    }
}


$a=new Dog('dog');
var_dump($a->cat->name);  ---> 打印结果是 cat
$b=clone $a;
$b->cat->name='catcat';
var_dump($a->cat->name);  ---> 打印结果是 catcat

如何解决上述的问题呢?有两种方式:一种是重写clone函数,一种是序列化之后赋值:

//方式一:重写clone函数
class Cat{
    public $name;
    public function __construct($name){
        $this->name=$name;
    }
}

class Dog{
    public $name;
    public $cat;
    public function __construct($name){
        $this->name=$name;
        $this->cat=new Cat('cat');
    }
    public function __clone(){
        $this->cat=clone $this->cat;
    }
}

$a=new Dog('dog');
var_dump($a->cat->name);  ---> 打印结果是 cat
$b=clone $a;
$b->cat->name='catcat';
var_dump($a->cat->name);  ---> 打印结果仍为 cat


//方式二:序列化之后赋值
class Cat{
    public $name;
    public function __construct($name){
        $this->name=$name;
    }
}

class Dog{
    public $name;
    public $cat;
    public function __construct($name){
        $this->name=$name;
        $this->cat=new Cat('cat');
    }
}

$a=new Dog('dog');
var_dump($a->cat->name);  ---> 打印结果是 cat
$b=serialize($a);
$b=unserialize($b);
$b->cat->name='catcat';
var_dump($a->cat->name);  ---> 打印结果仍为 cat

我们理清楚深浅复制之后,我们来看看如何使用原型模式创建对象:

abstract class Prototype{
	abstract public function __clone();
}

class BasketBall {
	public $name;
}

class Person extends Prototype{
	public $name;
	public $age;
	//对象属性
	public $hobby;
	public function __construct($attributes=array()){
		foreach($attributes as $key=>$attr){
			if(property_exists($this,$key)){
				$this->$key=$attr;
			}
		}
	}
	public function __clone(){
		$this->hobby = clone $this->hobby;
	}
}
//创建原型对象
$person = new Person(array('name'=>'example','age'=>0,'hobby'=>new Basketball()));
//需要对象的时候直接clone就好,不需要再实例化
$yaoming= clone $person;

以上就是原型模式的使用方法。

猜你喜欢

转载自blog.csdn.net/wx145/article/details/84575343