初探设计模式
初探设计模式
目录
知识要点
四个主要设计设计模式
模式知识要点
案例引用
他山之石
他山之石
扩展阅读
一. 设计模式知识要点
一个设计模式就是解决某一种特殊问题的推荐的最佳实践
设计模式并不是要定义一个解决方案,而是解决方案试图定位的问题
学习设计模式最难的事情就是理解什么样的设计模式适用于什么样的场景
设计模式的4个部分
它的名字
一个关于问题的讨论: 在什么场景下我们应该使用这种特定的设计模糊
解决方式,它并不是具体的实现代码,而是提供足够的信息,以便于我们可以根据这些信息来实现这种解决方式.
结论: 关于这种特定的设计模式的优点和缺点.
四人组对设计模式三种主要分类
创建型模式: 创建对象:将我们从需要手动来做的代码工作中解放出来 包括:建造者模式,工厂模式,原型模式和单例模式
结构型模式: 创建和使用复杂的结构. 包括:适配器模式,桥接模式,组合模式,装饰模式,外观模式,代理模式.
行为型模式: 描述对象在系统中的通信方式以及程序的逻辑控制流. 包括:命令模式,迭代器模式,观察者模式,状态模式,策略模式以及模板方法模式
二. 四个设计模式
1. 单例模式 (Singleton Pattern)
模式知识要点:
单例模式会限制应用程序,使其只能创建某一个特定类型的一个单一实例
所有实例均为指向同一属性(property)
对于初学者,我们可以使用一个静态属性来保证对于一个特定的类来说只存在一个单一的实例
从理论上来说,位于类外部的代码可以控制类的实例数量,然而,既然我们可以使用面向对象编程,并且一个类至少得有一个实例,那么在类中实现这种功能自然是最佳的选择
典型的应用场景是,当我们有一个全局的对象(比如配置类)或一个共享的资源(比如事件队列)时。
configuration class, session class, database class
案例引用:
<?php
namespace App;
class Singleton
{
private static $instance = NULL;
private $settings = [];
private function __construct()
{
}
private function __clone()
{
}
public static function getInstance()
{
if (self::$instance === NULL) {
self::$instance = new Singleton();
}
return self::$instance;
}
public function set($index, $value)
{
$this->settings[$index] = $value;
}
public function get($index)
{
return $this->settings[$index];
}
public function outputSet()
{
foreach ($this->settings as $k => $v) {
echo "<ul><li> {$k}: {$v} </li></ul>";
}
}
}
<?php
require_once "header.php";
$CONFIG = App\Singleton::getInstance();
var_dump($CONFIG->set("abc", "bbc"));
echo "<p>\$config['live']: {$CONFIG->get("abc")}";
$CONFIG->set("行到水穷处", "坐看云起时");
echo "<p>\$config['行到水穷处']: {$CONFIG->get("行到水穷处")}";
$TEST = App\Singleton::getInstance();
$TEST->set("China Daily", "Not CNN");
echo "<p>\$TEST['China Daily']: {$TEST->get("China Daily")}";
echo "<p>\$TEST['China Daily']: {$TEST->get("abc")}";
$TEST->set("此时相望不相闻", "愿逐月华流照君");
echo "<p>\$TEST['此时相望不相闻']: {$TEST->get("此时相望不相闻")}";
echo "<p>\$config['此时相望不相闻']: {$CONFIG->get("此时相望不相闻")}";
$TEST->outputSet();
output:
NULL
$config['live']: bbc
$config['行到水穷处']: 坐看云起时
$TEST['China Daily']: Not CNN
$TEST['China Daily']: bbc
$TEST['此时相望不相闻']: 愿逐月华流照君
$config['此时相望不相闻']: 愿逐月华流照君
abc: bbc
行到水穷处: 坐看云起时
China Daily: Not CNN
此时相望不相闻: 愿逐月华流照君
他山之石
[Code
Design Patterns: The Singleton Pattern](http://code.tutsplus.com/tutorials/design-patterns-the-singleton-pattern--cms-23073)
2. 工厂模式 (Factory Pattern)
模式知识要点:
工厂模式用于创建多种不同类型的类的多个对象
当程序编写时,并不能确定在生成对象的时候其确切的对象类型, 只有到程序运行时才会确定,在动态程序中,这种情况很常见
例如有一个抽象的基类,它的几个不同的派生子类需要立即被创建.因为我们一旦创建了一个对象,对这个对象的使用就会与期望一致,而不是关心它的确切类型
工厂模式通过通过一个静态方法实现,一个情况下该方法会命名为Create(), factory(), factoryMethod(), createInstance().
工厂模式其实也意味着可以很容易扩展
一个工厂模式的变种就是抽象工厂模式.然而工厂模式输出不同的对象,每一个都继承自同一个父类,抽象工厂则输出这些工厂类
案例引用:
<?php
namespace App;
use App\RectanlgeConstruct;
use App\Triangle;
abstract class ShapeFactory
{
public static function Create($type, array $sizes)
{
switch ($type) {
case "rectangle":
return new RectangleConstruct($sizes[0], $sizes[1]);
break;
case "triangle":
return new Triangle($sizes[0], $sizes[1], $sizes[2]);
break;
}
}
}
他山之石
3. 组合模式 (Composite Pattern)
模式知识要点:
组合模式适用于当我们的一个对象可能代表一个单一的实体,或者一个组合的实体,但是仍然需要通过同样的方式被使用的情况
要实现组合模式,我们通常会从一个抽象的基类开始,这个基类会被不同的子类扩展.基类需要知道增加或者移除"叶子"(也就是组合的条目)的方法.基类同时也需要知道这个组合或者它的元素需要做的功能.
案例引用:
<?php
namespace App;
abstract class WorkUnit
{
protected $tasks = [];
protected $name = NULL;
public function __construct($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
abstract public function add(Employee $e);
abstract public function remove(Employee $e);
abstract public function assignTask($task);
abstract public function completeTask($task);
}
<?php
namespace App;
class Employee extends WorkUnit
{
public function add(Employee $e)
{
return false;
}
public function remove(Employee $e)
{
return false;
}
public function assignTask($task)
{
$this->tasks[] = $task;
echo "<p>A new task has been assigned to {$this->getName()}. It will be done by {$this->getName()} alone. </p>";
}
public function completeTask($task)
{
$index = array_search($task, $this->tasks);
unset($this->tasks[$index]);
echo "<p>The \$task task has been completed by employee {$this->getName()}. </p>";
}
}
<?php
namespace App;
use App\Employee;
class Team extends WorkUnit
{
private $employees = [];
public function add(Employee $e)
{
$this->employees[] = $e;
echo "<p>{$e->getName()} has been added to team {$this->getName()} </p>";
}
public function remove(Employee $e)
{
$index = array_search($e, $this->employees);
unset($this->employees[$index]);
echo "<p> {$e->getName()} has been removed fromteam {$this->getName()}. </p>";
}
public function assignTask($task)
{
$this->tasks[] = $task;
echo "<p>A nes task has been assigned to team {$this->getName()}. It should be easy to do with {$this->getCount()} team member. </p>";
}
public function completeTask($task)
{
$index = array_search($task, $this->tasks);
unset($this->tasks[$index]);
echo "<p> {$task} task has been complete by team {$this->getName()}. </p>";
}
public function getCount()
{
return count($this->employees);
}
}
<?php
require_once "header.php";
use App\Team;
use App\Employee;
$alpha = new Team("Alpha");
$john = new Employee("John");
$cynthia = new Employee("cynthia");
$rashid = new Employee("rashid");
$alpha->add($john);
$alpha->add($rashid);
$alpha->assignTask("Do something great");
$cynthia->assignTask("Do something grand");
$alpha->completeTask("Do something great");
$alpha->remove($john);
他山之石
4. 策略模式 (Strategy Pattern)
模式知识要点:
策略模式会立即改变一个算法,当我们使用的类比较简单,但又不互相关联,只是在特定行为上有所差异的场景下,策略模式会十分有用.
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.
案例引用:
<?php
namespace App;
interface Sort
{
function Sort(array $list);
}
<?php
namespace App;
class MultiAlphaSort implements Sort
{
private $index;
private $order;
public function __construct($index, $order = "ascending")
{
$this->index = $index;
$this->order = $order;
}
public function Sort(array $list)
{
if ($this->order == "ascending") {
uasort($list, array($this, "ascSort"));
} else {
uasort($list, array($this, "descSort"));
}
return $list;
}
public function ascSort($x, $y)
{
return strcasecmp($x[$this->index], $y[$this->index]);
}
public function descSort($x, $y)
{
return strcasecmp($y[$this->index], $x[$this->index]);
}
}
<?php
namespace App;
class MultiNumberSort implements Sort
{
private $index;
private $order;
public function __construct($index, $order = "ascending")
{
$this->index = $index;
$this->order = $order;
}
public function Sort(array $list)
{
if ($this->order == "ascending") {
uasort($list, array($this, "ascSort"));
} else {
uasort($list, array($this, "descSort"));
}
return $list;
}
public function ascSort($x, $y)
{
return ($x[$this->index] > $y[$this->index]);
}
public function descSort($x, $y)
{
return ($x[$this->index] < $y[$this->index]);
}
}
<?php
require_once "header.php";
use App\Sort;
use App\MultiAlphaSort;
use App\MultiNumberSort;
class StudentList
{
private $students = [];
public function __construct($list)
{
$this->students = $list;
}
public function sort(Sort $type)
{
$this->students = $type->sort($this->students);
}
public function display()
{
echo "<ol>";
foreach ($this->students as $student) {
echo "<li>{$student["name"]} -> {$student["grade"]}</li>" ;
}
echo "</ol>";
}
}
$students = [
256 => ["name" => "Jon", "grade" => 98.5 ],
2 => ["name" => "Vance", "grade" => 85.1 ],
9 => ["name" => "Stephen", "grade" => 94.5 ],
364 => ["name" => "Steve", "grade" => 85.1 ],
256 => ["name" => "Rob", "grade" => 74.6 ]
];
$list = new StudentList($students);
echo "<h2> Origianl Array </h2>";
$list->display();
$list->sort(new MultiAlphaSort("name"));
echo "<h2> Sort By Name Default Sort</h2>";
$list->display();
$list->sort(new MultiAlphaSort("name", "descending"));
echo "<h2> Sort By Name Descend</h2>";
$list->display();
$list->sort(new MultiNumberSort("grade"));
echo "<h2> Sort By Grade Default</h2>";
$list->display();
$list->sort(new MultiNumberSort("grade", "descending"));
echo "<h2> Sort By Grade </h2>";
$list->display();
他山之石