淺談設計模式之原型模式
阿新 • • 發佈:2018-11-28
背景知識:
- 我們常說的設計模式其實是一種程式碼規範,遵從設計模式所編寫的程式碼並不是最高效的,但是是可維護的。
- 設計模式主要有三類:建立型設計模式,結構型設計模式以及行為型設計模式。
- 設計模式遵循的幾個原則:開閉原則,里氏代換原則,依賴倒轉原則,單一職責原則,合成複用原則,介面隔離原則,最小知識原則。
本文主要講述原型模式,原型模式和我們在上一篇中講的單例模式相似,都是關於物件的。只是單例模式的物件只建立一次,之後所有的操作都是圍繞這一個物件展開的。而原型模式的目的則是為了獲得新的物件,通過克隆的方式減少不斷例項化所帶來的開銷。
在附上原型模式的事例程式碼之前,我們先來聊聊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;
以上就是原型模式的使用方法。