今回は、PHP プロトタイプ モードの事例分析をお届けします。PHP プロトタイプ モードを使用する際の 注意事項 は何ですか?実際の事例を見てみましょう。
プロトタイプ デザイン パターンは、クローン作成手法を使用してインスタンス化されたオブジェクトをコピーするため、興味深いものです。ここで、インスタンスはバッチでインスタンス化された具体的なクラスです。プロトタイプ デザイン パターンの目的は、オーバーヘッドを削減することです。クローン作成を使用してオブジェクトをインスタンス化する方法。クラスから新しいオブジェクトをインスタンス化する代わりに、既存のインスタンスのクローンを使用できますPHP で使用されるデザイン パターンのプロトタイピングの鍵は、その方法を理解することです。組み込み関数 clone()
を使用するには、boy インスタンス $boy を複製することによって cloneBoy インスタンスが作成されます。これは、$boy と同じプロパティにアクセスし、直接インスタンスのようにこれらのプロパティを変更できます。 Boy クラスの
クローンされたインスタンスの場合、clone キーワードはこのインスタンスのクラスの別のインスタンスをインスタンス化します (clone キーワードを使用すると、クラスのコピーを作成できます。可能であれば、オブジェクトの clone
メソッドは自動的に呼び出されますが、オブジェクトの clone メソッドは
メソッドを直接呼び出すことはできません)。このプロセスに関して注意すべき点は、クローン作成では コンストラクター内のアクションが開始されないことです。 .clone()
.
<?php abstract class CloneObject { public $name; public $picture; abstract function clone(); } class Boy extends CloneObject { public function construct() { $this->face = "handsome"; $this->name = "chenqionghe"; } public function display() { echo 'look : '.$this->face;; echo '<br />'.$this->name.'<br />'; } public function clone() {} } $boy = new Boy(); $boy->display(); $cloneBoy = clone $boy; $cloneBoy->face = "still handsome"; $cloneBoy->display();
运行结果如下
look : handsome
chenqionghe
look : still handsome
chenqionghe
$cloneBoy实例是通过克隆Boy的实例$boy, 它可以像$boy一样访问相同的属性, 而且像Boy类的直接实例一样改变这些属性.
注意: 对于所克隆的实例 , clone关键字会为该实例的类实例化另一个实例(使用克隆关键字可以创建一个类的副本, 如果可能, 会自动调用对象的clone
方法, 但不能直接调用 对象的clone
例としてショウジョウバエの研究を見てみましょう。研究の目標は、プロトタイプのショウジョウバエを構築し、突然変異が発生したら、この突然変異体のショウジョウバエを構築することです
抽象クラスインターフェースと具象実装プロトタイプ (IPrototype) の 2 つの具象クラス実装は、それぞれ異なる性別のショウジョウバエを表し、異なる性別の性別変数と行動を含みます。 IPrototype の 2 つの実装の違いは性別に反映され、一方は MALE、もう一方は FEMAIL です。雄のミバエは $mated のブール変数を持ちます。雄のミバエが交尾すると、このブール変数は次のようになります。メスのショウジョウバエには、このオスのショウジョウバエの繁殖能力 (産卵された卵の数) を示す数値が含まれる $fecundity 変数があります:
MaleProto.php
<?php abstract class IPrototype { public $eyeColor; public $winBeat; public $unitEypes; abstract function clone(); }
<?php include_once('IPrototype.php'); class MaleProto extends IPrototype { const gender = "MALE"; public $mated; public function construct() { $this->eyeColor = "red"; $this->winBeat = "220"; $this->unitEypes = "760"; } public function clone(){} }
Client
プロトタイプ設計モードでは、Client クラスは確かに不可欠な部分です。その理由は、サブクラスの特定の実装がインスタンスのテンプレートとして使用されるためです。同じテンプレートを使用したインスタンスのクローン作成は Client クラスによって行われますClient.php
<?php include_once('IPrototype.php'); class FemaleProto extends IPrototype { const gender = "FEMAIL"; public $fecundity; public function construct() { $this->eyeColor = "red"; $this->winBeat = "220"; $this->unitEypes = "760"; } public function clone(){} }
目の色: 赤
羽のビート/秒: 220目の単位: 760性別: 男性交尾: true目の色: 赤
羽の鼓動/秒: 220目の単位: 760
性別: FEMAIL卵の数: 186 個目の色: 紫ソフトウェア エンジニアリング会社は、製品の作成を担当する典型的な組織です。 , 管理部門 (Management) はリソースの調整と整理を担当し、マーケティング部門 (Marketing) は製品の販売、プロモーション、マーケティング全体を担当します羽の鼓動/秒: 220
目の単位: 760
性別: FEMAIL
卵の数: 92
プロトタイプ モードでは、クローン作成プロセスを通じて特定のプロトタイプを使用するのは顧客に依存します。この設計プロセスでは、クローン作成はプロトタイピングの重要な要素であるため、顧客はクローン作成の完了に参加します。したがって、顧客は単なるリクエストクラスではなく、基本的な参加者です。
現代のエンタープライズ組織
創造的なデザインパターンの観点から見ると、現代のエンタープライズ組織は、多くの場合、複雑で巨大です。オブジェクト指向プログラミングと同様に、多くの共通の特性をモデル化する必要があります。
インターフェースのカプセル化。
在这个原型实现中,首先为程序的接口(一个抽象类)增加OOP,与所有原型接口一样,这个接口包含一个克隆操作.另外它还包含一些抽象和具体的获取方法和设置方法.其中有一个抽象获取方法/设置方法对,但要由3个具体原型实现为这个抽象获取方法/设置方法对提供具体实现.其他获取方法和设置方法分分别应用于员工名,ID码和照片等属性.注意所有这些属性都是保护属性(protected),所以尽管具体的获取方法和设置方法有公共可见性,但由于操作中使用的属性具有保护和可见性,这就提供了某种程度的封装:
<?php abstract class IAcmePrototype { protected $name; protected $id; protected $employeePic; protected $department; //部门 abstract function setDept($orgCode); abstract function getDept(); //名字 public function setName($emName) { $this->name = $emName; } public function getName() { return $this->name; } //ID public function setId($emId) { $this->id = $emId; } public function getId() { return $this->id; } //雇员图像 public function setPic($ePic) { $this->employeePic = $ePic; } public function getPic() { return $this->employeePic; } abstract function clone(); }
利用这些获取方法和设置方法, 所有属性的值都通过继承的保护变量来设置.采用这种设计, 扩展类及其实例可以得到更好的封装.
接口实现
3个IAcmePrototype子类都必须实现"dept"抽象方法以及clone()
方法.类似地, 每个具体原型类还包含一个常量UNIT,它提供一个赋值,可以由实例(包括克隆的对象)作为标识
首先来看市场部的Marketing类:
Marketing.php
<?php include_once('IAcmePrototype.php'); class Marketing extends IAcmePrototype { const UNIT = "Marketing"; private $sales = "sales"; private $promotion = "promotion"; private $strategic = "strategic planning"; public function setDept($orgCode) { switch($orgCode) { case 101: $this->department = $this->sales; break; case 102: $this->department = $this->promotion; break; case 103: $this->department = $this->strategic; break; default : $this->department = "未识别的市场部"; } } public function getDept() { return $this->department; } public function clone() {} }
setDept()
方法的实现使用了一个参数.并不是直接输入市场部的部门,这个方法的参数是一个数字码, 通过一个switch语句,限制了3种可接受的情况和默认情况,别外两个原型实现也类似
Management.php
<?php include_once('IAcmePrototype.php'); class Management extends IAcmePrototype { const UNIT = "Management"; private $research = "research"; private $plan = "planning"; private $operations = "operations"; public function setDept($orgCode) { switch($orgCode) { case 201: $this->department = $this->research; break; case 202: $this->department = $this->plan; break; case 203: $this->department = $this->operations; break; default : $this->department = "未识别的管理部"; } } public function getDept() { return $this->department; } public function clone() {} }
Engineering.php
<?php include_once('IAcmePrototype.php'); class Engineering extends IAcmePrototype { const UNIT = "Engineering"; private $development = "development"; private $design = "design"; private $sysAd = "system administration"; public function setDept($orgCode) { switch($orgCode) { case 301: $this->department = $this->development; break; case 302: $this->department = $this->design; break; case 303: $this->department = $this->sysAd; break; default : $this->department = "未识别的工程部"; } } public function getDept() { return $this->department; } public function clone() {} }
以上这3个具体原型实现分别有其特定用途,不过它们都符合接口,可以创建各个原型实现的一个实例, 然后根据需要克隆多个实例.这个克隆的工作由Client类完成
客户
客户的设置非常简单: 分别创建各个具体原型的一个实例, 然后按以下列表来克隆各个实例:
市场部门实例:
-----市场部门克隆
-----市场部门克隆
管理部门实例
-----管理部门克隆
工程部门实例
-----工程部门克隆
-----工程部门克隆
将来只使用这些克隆对象.使用获取方法和设置方法将各个特定情况的信息赋给这些克隆对象.以下是Client的实现
Client.php
<?php function autoload($class_name) { include_once $class_name.'.php'; } class Client { private $market; private $manage; private $engineer; public function construct() { $this->makeConProto(); $Tess = clone $this->market; $this->setEmployee($Tess, "Tess Smith" , 101, 'ts101-1234', 'tess.png'); $this->showEmployee($Tess); $Jacob = clone $this->market; $this->setEmployee($Jacob, "Jacob Jones" , 101, 'jj101-2234', 'jacob.png'); $this->showEmployee($Jacob); $Ricky = clone $this->manage; $this->setEmployee($Ricky, "Ricky Rodriguez" , 203, 'rr101-5634', 'ricky.png'); $this->showEmployee($Ricky); $Olivaia = clone $this->engineer; $this->setEmployee($Olivaia, "Olivaia Perez" , 302, 'op301-1278', 'olivia.png'); $this->showEmployee($Olivaia); $John = clone $this->engineer; $this->setEmployee($John, "John Jacson" , 101, 'jj301-14548', 'john.png'); $this->showEmployee($John); } private function makeConProto() { $this->market = new Marketing(); $this->manage = new Management(); $this->engineer = new Engineering(); } private function showEmployee(IAcmePrototype $employeeNow) { $px = $employeeNow->getPic(); echo "<img src=$px width='150' height='150' /><br />"; echo $employeeNow->getName().'<br />'; echo $employeeNow->getDept().':'.$employeeNow::UNIT.'<br />'; echo $employeeNow->getId().'<hr />'; } private function setEmployee(IAcmePrototype $employeeNow, $nm, $dp, $id, $px) { $employeeNow->setName($nm); $employeeNow->setDept($dp); $employeeNow->setId($id); $employeeNow->setPic($px); } } $worker = new Client();
解释:
客户Client的构造函数类包含3个私有属性, 用来分别实例化3个具体原型类. makeConPro()
方法生成必要的实例.
接下来,使用克隆技术创建一个"员工"实例.然后,这个实例向一个设置方法setEmployee()发送特定的实例信息,这个设置方法使用IAcmePrototype接口类型提示,不过需要说明, 它只对第一个参数使用类型提示,其他参数都没有类型提示, 并不要求它们派生自IAcmePrototype接口.克隆"员工"可以使用IAcmePrototype抽象类的所有设置方法以及具体原型类实现的setDept()方法.
要使用各个员工的数据,Client类可以使用继承的获取方法.以下是运行Client输出的结果
Tess Smith
sales:Marketing
ts101-1234
Jacob Jones
sales:Marketing
jj101-2234
Ricky Rodriguez
operations:Management
rr101-5634
Olivaia Perez
design:Engineering
op301-1278
John Jacson
未识别的工程部:Engineering
jj301-14548
可以根据需要增加更多的克隆, 而且只需要对具体原型类完成一次实例化.使用原型模式时, 并不是建立具体类的多个实例,而只需要一个类实例化和多个克隆.
完成修改,增加特性
要记住,最重要(可能也是最基本)的是, 设计模式允许开发人员修改和增补程序,而不必一切从头开始.例如, 假设总裁决定公司增加一个新的部门,比如研究部门(Research), 这会很难吗?一点也不难.Research可以扩展IAcmePrototype抽象类, 然后实现抽象获取方法和设置方法来反映这个研究部门的组织.需要说明,Client类中获取方法和设置方法使用的代码提示指示一个接口,而不是一个抽象类的具体实现.所以, 只要增加的单元正确地实现了这个接口,就能顺利地增加到应用中, 而不会带来波动,也不需要对程序中的其他参与者进行重构.
より具体的なクラスを追加できるだけでなく、混乱を引き起こすことなく個々のクラスを簡単に変更できます。たとえば、この組織のマーケティング部門が、既存の部門に加えて特別なオンライン マーケティング部門が必要であると決定したとします。このように、switch/case 操作には、新しい部門を記述するための新しいブランチ (ケース) と新しいプライベート属性 (変数) が必要です。この変更は、他の参加者に影響を与えることなく、別のクラスに凍結されます。損傷を引き起こすことはありませんが、アプリケーションの規模が大きくなるほど、これはより重要になります。プロトタイプの設計パターンは、一貫性をサポートするだけでなく、柔軟な変更もサポートすることがわかります。
PHP の世界におけるプロトタイプ
PHP はサーバーサイド言語であり、MySQL データベース と対話するための重要なツールであるため、データベースの最初の要素に個別のオブジェクトを作成する代わりに、プロトタイピング パターンを使用して PHP を作成できます。具象クラスのインスタンスを作成し、データベース内のデータを使用して残りのインスタンス (レコード) をクローンします。
クローン作成プロセスを直接インスタンス化のプロセスと比較して理解した後、「何が意味があるの? 違いは何ですか?」と疑問に思うかもしれません。 " 言い換えれば、なぜクローン作成はオブジェクトを直接インスタンス化するよりも必要なリソースが少ないのですか? 違いは直接はわかりません。クローン作成によってオブジェクトがインスタンス化されるとき、コンストラクターは開始されません。クローンは、元のクラスのプロパティをすべて取得します。インスタンス化されたオブジェクトに渡されるすべての値を継承するだけでなく、コンストラクターによって生成され、オブジェクトのプロパティに格納されるすべての値は、クローンされたオブジェクトの一部になります。そのため、戻り値のコンストラクターはありません。クローン オブジェクトはコンストラクターによって生成された値にアクセスする必要がありますが、アクセスできないということは、インスタンスが必要な情報をすべて備え、このデータをクローン オブジェクトに渡すことができるようにクラスをリファクタリングする必要があることを意味します。つまり、プロトタイプ モードは、さまざまな種類の PHP プロジェクトに非常に適しています。問題を解決する必要がある場合、またはモデルを作成する必要がある場合は、プロトタイプ モードを使用できます。この記事にはさらに興味深い内容が含まれています。php 中国語 Web サイトの他の関連記事にも注目してください。
推奨書籍:
PHP Closure Principle (OCP) ユースケース分析以上がPHPプロトタイプパターンのケース分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。