摘要:我們分三篇文章來(lái)總結(jié)一下設(shè)計(jì)模式在中的應(yīng)用,這是第一篇?jiǎng)?chuàng)建型模式。二提煉設(shè)計(jì)模式的幾個(gè)原則開(kāi)閉原則模塊應(yīng)對(duì)擴(kuò)展開(kāi)放,而對(duì)修改關(guān)閉。工廠模式實(shí)現(xiàn)定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定實(shí)例化哪一個(gè)類。設(shè)計(jì)模式的第一部分,創(chuàng)建型模式就總結(jié)完了。
我們分三篇文章來(lái)總結(jié)一下設(shè)計(jì)模式在PHP中的應(yīng)用,這是第一篇?jiǎng)?chuàng)建型模式。
一、設(shè)計(jì)模式簡(jiǎn)介
首先我們來(lái)認(rèn)識(shí)一下什么是設(shè)計(jì)模式:
設(shè)計(jì)模式是一套被反復(fù)使用、容易被他人理解的、可靠的代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。
設(shè)計(jì)模式不是Java的專利,我們用面向?qū)ο蟮姆椒ㄔ赑HP里也能很好的使用23種設(shè)計(jì)模式。
那么我們常說(shuō)的架構(gòu)、框架和設(shè)計(jì)模式有什么關(guān)系呢?
架構(gòu)是一套體系結(jié)構(gòu),是項(xiàng)目的整體解決方案;框架是可供復(fù)用的半成品軟件,是具體程序代碼。架構(gòu)一般會(huì)涉及到采用什么樣的框架來(lái)加速和優(yōu)化某部分問(wèn)題的解決,而好的框架代碼里合理使用了很多設(shè)計(jì)模式。
二、提煉設(shè)計(jì)模式的幾個(gè)原則:
開(kāi)閉原則:模塊應(yīng)對(duì)擴(kuò)展開(kāi)放,而對(duì)修改關(guān)閉。
里氏代換原則:如果調(diào)用的是父類的話,那么換成子類也完全可以運(yùn)行。
依賴倒轉(zhuǎn)原則:抽象不依賴細(xì)節(jié),面向接口編程,傳遞參數(shù)盡量引用層次高的類。
接口隔離原則:每一個(gè)接口只負(fù)責(zé)一種角色。
合成/聚合復(fù)用原則:要盡量使用合成/聚合,不要濫用繼承。
三、設(shè)計(jì)模式的功用?
設(shè)計(jì)模式能解決:
替換雜亂無(wú)章的代碼,形成良好的代碼風(fēng)格
代碼易讀,工程師們都能很容易理解
增加新功能時(shí)不用修改接口,可擴(kuò)展性強(qiáng)
穩(wěn)定性好,一般不會(huì)出現(xiàn)未知的問(wèn)題
設(shè)計(jì)模式不能解決:
設(shè)計(jì)模式是用來(lái)組織你的代碼的模板,而不是直接調(diào)用的庫(kù);
設(shè)計(jì)模式并非最高效,但是代碼的可讀性和可維護(hù)性更重要;
不要一味追求并套用設(shè)計(jì)模式,重構(gòu)時(shí)多考慮;
四、設(shè)計(jì)模式分類
1、創(chuàng)建型模式:
單例模式、工廠模式(簡(jiǎn)單工廠、工廠方法、抽象工廠)、創(chuàng)建者模式、原型模式。
2、結(jié)構(gòu)型模式:
適配器模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式、代理模式。
3、行為型模式:
模版方法模式、命令模式、迭代器模式、觀察者模式、中介者模式、備忘錄模式、解釋器模式、狀態(tài)模式、策略模式、職責(zé)鏈模式、訪問(wèn)者模式。
五、創(chuàng)建型設(shè)計(jì)模式
1、單例模式
目的:保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。
應(yīng)用場(chǎng)景:數(shù)據(jù)庫(kù)連接、緩存操作、分布式存儲(chǔ)。
/**
單例模式
*
*/
class DbConn
{
privatestatic $_instance = null;
protectedstatic $_counter = 0;
protected$_db;
//私有化構(gòu)造函數(shù),不允許外部創(chuàng)建實(shí)例
privatefunction __construct()
{
self::$_counter+= 1;
}
publicfunction getInstance()
{
if(self::$_instance == null)
{
self::$_instance= new DbConn();
}
returnself::$_instance;
}
publicfunction connect()
{
echo"connected: ".(self::$_counter)."n";
return$this->_db;
}
}
/*
不使用單例模式時(shí),刪除構(gòu)造函數(shù)的private后再測(cè)試,第二次調(diào)用構(gòu)造函數(shù)后,_counter變成2
*/
// $conn = new DbConn();
// $conn->connect();
// $conn = new DbConn();
// $conn->connect();
//使用單例模式后不能直接new對(duì)象,必須調(diào)用getInstance獲取
$conn = DbConn::getInstance();
$db = $conn->connect();
//第二次調(diào)用是同一個(gè)實(shí)例,_counter還是1
$conn = DbConn::getInstance();
$db = $conn->connect();
?>
特別說(shuō)明:這里getInstance里有if判斷然后再生成對(duì)象,在多線程語(yǔ)言里是會(huì)有并發(fā)問(wèn)題的。例如java的解決方案有二個(gè),給方法加上synchronized關(guān)鍵詞變成同步,或者把_instanc的初始化提前放到類成員變量定義時(shí),但是這2種方式php都不支持。不過(guò)因?yàn)閜hp不支持多線程所以不需要考慮這個(gè)問(wèn)題了。
2、工廠模式
實(shí)現(xiàn):定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定實(shí)例化哪一個(gè)類。
應(yīng)用場(chǎng)景:眾多子類并且會(huì)擴(kuò)充、創(chuàng)建方法比較復(fù)雜。
/**
*
工廠模式
*/
//抽象產(chǎn)品
interface Person {
public function getName();
}
//具體產(chǎn)品實(shí)現(xiàn)
class Teacher implements Person {
function getName() {
return "老師n";
}
}
class Student implements Person {
function getName() {
return "學(xué)生n";
}
}
//簡(jiǎn)單工廠
class SimpleFactory {
publicstatic function getPerson($type) {
$person= null;
if($type == "teacher") {
$person= new Teacher();
}elseif ($type == "student") {
$person= new Student();
}
return$person;
}
}
//簡(jiǎn)單工廠調(diào)用
class SimpleClient {
functionmain() {
//如果不用工廠模式,則需要提前指定具體類
//$person = new Teacher();
//echo $person->getName();
//$person = new Student();
//echo $person->getName();
//用工廠模式,則不需要知道對(duì)象由什么類產(chǎn)生,交給工廠去決定
$person= SimpleFactory::getPerson("teacher");
echo$person->getName();
$person= SimpleFactory::getPerson("student");
echo$person->getName();
}
}
//工廠方法
interface CommFactory {
public function getPerson();
}
//具體工廠實(shí)現(xiàn)
class StudentFactory implements CommFactory{
function getPerson(){
return new Student();
}
}
class TeacherFactory implements CommFactory{
function getPerson() {
return new Teacher();
}
}
//工廠方法調(diào)用
class CommClient {
static function main() {
$factory = new TeacherFactory();
echo$factory->getPerson()->getName();
$factory = new StudentFactory();
echo$factory->getPerson()->getName();
}
}
//抽象工廠模式另一條產(chǎn)品線
interface Grade {
functiongetYear();
}
//另一條產(chǎn)品線的具體產(chǎn)品
class Grade1 implements Grade {
publicfunction getYear() {
return"2003級(jí)";
}
}
class Grade2 implements Grade {
publicfunction getYear() {
return"2004級(jí)";
}
}
//抽象工廠
interface AbstractFactory {
functiongetPerson();
functiongetGrade();
}
//具體工廠可以產(chǎn)生每個(gè)產(chǎn)品線的產(chǎn)品
class Grade1TeacherFactory implementsAbstractFactory {
publicfunction getPerson() {
returnnew Teacher();
}
publicfunction getGrade() {
returnnew Grade1();
}
}
class Grade1StudentFactory implementsAbstractFactory {
publicfunction getPerson() {
returnnew Student();
}
publicfunction getGrade() {
returnnew Grade1();
}
}
class Grade2TeacherFactory implementsAbstractFactory {
publicfunction getPerson() {
returnnew Teacher();
}
publicfunction getGrade() {
returnnew Grade2();
}
}
//抽象工廠調(diào)用
class FactoryClient {
functionprintInfo($factory) {
echo$factory->getGrade()->getYear().$factory->getPerson()->getName();
}
functionmain() {
$client= new FactoryClient();
$factory= new Grade1TeacherFactory();
$client->printInfo($factory);
$factory= new Grade1StudentFactory();
$client->printInfo($factory);
$factory= new Grade2TeacherFactory();
$client->printInfo($factory);
}
}
//簡(jiǎn)單工廠
//SimpleClient::main();
//工廠方法
//CommClient::main();
//抽象工廠
FactoryClient::main();
?>
三種工廠的區(qū)別是,抽象工廠由多條產(chǎn)品線,而工廠方法只有一條產(chǎn)品線,是抽象工廠的簡(jiǎn)化。而工廠方法和簡(jiǎn)單工廠相對(duì),大家初看起來(lái)好像工廠方法增加了許多代碼但是實(shí)現(xiàn)的功能和簡(jiǎn)單工廠一樣。
但本質(zhì)是,簡(jiǎn)單工廠并未嚴(yán)格遵循設(shè)計(jì)模式的開(kāi)閉原則,當(dāng)需要增加新產(chǎn)品時(shí)也需要修改工廠代碼。但是工廠方法則嚴(yán)格遵守開(kāi)閉原則,模式只負(fù)責(zé)抽象工廠接口,具體工廠交給客戶去擴(kuò)展。在分工時(shí),核心工程師負(fù)責(zé)抽象工廠和抽象產(chǎn)品的定義,業(yè)務(wù)工程師負(fù)責(zé)具體工廠和具體產(chǎn)品的實(shí)現(xiàn)。只要抽象層設(shè)計(jì)的好,框架就是非常穩(wěn)定的。
3、創(chuàng)建者模式
在創(chuàng)建者模式中,客戶端不再負(fù)責(zé)對(duì)象的創(chuàng)建與組裝,而是把這個(gè)對(duì)象創(chuàng)建的責(zé)任交給其具體的創(chuàng)建者類,把組裝的責(zé)任交給組裝類,客戶端支付對(duì)對(duì)象的調(diào)用,從而明確了各個(gè)類的職責(zé)。
應(yīng)用場(chǎng)景:創(chuàng)建非常復(fù)雜,分步驟組裝起來(lái)。
/**
優(yōu)才網(wǎng)公開(kāi)課示例代碼
*
創(chuàng)建者模式
*/
//購(gòu)物車
class ShoppingCart {
//選中的商品
private $_goods = array();
//使用的優(yōu)惠券
private $_tickets = array();
publicfunction addGoods($goods) {
$this->_goods[]= $goods;
}
public function addTicket($ticket) {
$this->_tickets[] = $ticket;
}
public function printInfo() {
printf("goods:%s,tickets:%sn", implode(",", $this->_goods),
implode(",",$this->_tickets));
}
}
//假如我們要還原購(gòu)物車的東西,比如用戶關(guān)閉瀏覽器后再打開(kāi)時(shí)會(huì)根據(jù)cookie還原
$data = array(
"goods"=> array("衣服", "鞋子"),
"tickets"=> array("減10"),
);
//如果不使用創(chuàng)建者模式,則需要業(yè)務(wù)類里一步步還原購(gòu)物車
// $cart = new ShoppingCart();
// foreach ($data["goods"] as $goods) {
// $cart->addGoods($goods);
// }
// foreach ($data["tickets"] as $ticket) {
// $cart->addTicket($ticket);
// }
// $cart->printInfo();
// exit;
//我們提供創(chuàng)建者類來(lái)封裝購(gòu)物車的數(shù)據(jù)組裝
class CardBuilder {
private$_card;
function__construct($card) {
$this->_card= $card;
}
functionbuild($data) {
foreach($data["goods"] as $goods) {
$this->_card->addGoods($goods);
}
foreach($data["tickets"] as $ticket) {
$this->_card->addTicket($ticket);
}
}
functiongetCrad() {
return$this->_card;
}
}
$cart = new ShoppingCart();
$builder = new CardBuilder($cart);
$builder->build($data);
echo "after builder:n";
$cart->printInfo();
?>
可以看出,使用創(chuàng)建者模式對(duì)內(nèi)部數(shù)據(jù)復(fù)雜的對(duì)象封裝數(shù)據(jù)組裝過(guò)程后,對(duì)外接口就會(huì)非常簡(jiǎn)單和規(guī)范,增加修改新數(shù)據(jù)項(xiàng)也不會(huì)對(duì)外部造成任何影響。
原型模式
用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過(guò)拷貝這個(gè)原型來(lái)創(chuàng)建新的對(duì)象。
應(yīng)用場(chǎng)景:類的資源非常多、性能和安全要求,一般和工廠方法結(jié)合使用。
/**
原型模式
//聲明一個(gè)克隆自身的接口
interface Prototype {
function copy();
}
//產(chǎn)品要實(shí)現(xiàn)克隆自身的操作
class Student implements Prototype {
//簡(jiǎn)單起見(jiàn),這里沒(méi)有使用getset
public $school;
public $major;
public$name;
publicfunction __construct($school, $major, $name) {
$this->school= $school;
$this->major= $major;
$this->name= $name;
}
publicfunction printInfo() {
printf("%s,%s,%sn",$this->school, $this->major, $this->name);
}
public function copy() {
return clone $this;
}
}
$stu1 = new Student("清華大學(xué)", "計(jì)算機(jī)", "張三");
$stu1->printInfo();
$stu2 = $stu1->copy();
$stu2->name = "李四";
$stu2->printInfo();
?>
這里可以看到,如果類的成員變量非常多,如果由外部創(chuàng)建多個(gè)新對(duì)象再一個(gè)個(gè)賦值,則效率不高代碼冗余也容易出錯(cuò),通過(guò)原型拷貝復(fù)制自身再進(jìn)行微小修改就是另一個(gè)新對(duì)象了。
設(shè)計(jì)模式的第一部分,創(chuàng)建型模式就總結(jié)完了。下面還有兩部分結(jié)構(gòu)型設(shè)計(jì)模式和行為型設(shè)計(jì)模式下次繼續(xù)分享。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/22753.html
摘要:前端還有一個(gè)很重要的事就是設(shè)計(jì)。,中文版譯名為認(rèn)知與設(shè)計(jì)理解設(shè)計(jì)準(zhǔn)則。實(shí)驗(yàn)室是布拉德弗羅斯特依照這個(gè)設(shè)計(jì)系統(tǒng)所建立的一套工具,可以前往的來(lái)試試。中文翻譯為流暢設(shè)計(jì)體系,是微軟于年開(kāi)發(fā)的設(shè)計(jì)語(yǔ)言。微軟于年月日的開(kāi)發(fā)者大會(huì)上公開(kāi)了該設(shè)計(jì)體系。 showImg(https://segmentfault.com/img/bVbkgFI?w=1142&h=640); 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳Gi...
摘要:,美國(guó)著名程序員風(fēng)險(xiǎn)投資家博客和技術(shù)作家。,從年以來(lái),獲獎(jiǎng)的計(jì)算機(jī)科學(xué)方面的論文收集。截至年月,已收集超過(guò)萬(wàn)篇預(yù)印本。其中的分類可以認(rèn)為也是一個(gè)論文的集散地。 showImg(https://segmentfault.com/img/bVbjVFa?w=1142&h=640); 這個(gè)是我訂閱 陳皓老師在極客上的專欄《左耳聽(tīng)風(fēng)》,我整理出來(lái)是為了自己方便學(xué)習(xí),同時(shí)也分享給你們一起學(xué)習(xí),當(dāng)...
閱讀 992·2023-04-25 14:20
閱讀 1868·2021-11-24 10:20
閱讀 3766·2021-11-11 16:55
閱讀 2905·2021-10-14 09:42
閱讀 3467·2019-08-30 15:56
閱讀 1144·2019-08-30 15:55
閱讀 1063·2019-08-30 15:44
閱讀 771·2019-08-29 11:28