“为什么需求又变了”,“又得重构了”,“代码太乱了,不能复用啊”,“咦,这段代码以前在哪写过啊,怎么还得写一遍呢”…… 是改变的时候了,如果你不想做一个默默无闻并且每天累的要死的码农,那就赶紧学习设计模式吧,他会让你站在另一个高度看问题,让你成为大家的仰慕者,也会让团队沉淀出很多复用的东西,既然设计模式好处这么多,那么我就给大家讲一下常用的设计模式吧。
所谓设计模式,就是解决特定问题的方案,很多问题前人已经解决过N次了,已经形成了很好的解决方案,我们可以学习并应用之。
1、单例模式
<?php
/**
* 策略模式,当类中实现了多种实现方式的时候,最好把这些方式
* 提取出来放到自己的类型中,而不是通过继承去支持这些实现,
* 下面的例子是一个计算方式是加10,一个是加20,这样无论有多少
* 中算法都可以无限扩展,问题也可以无线扩展,这样不会有代码冗余
*/
abstract class Question{
protected $marker;
public function __construct(Marker $marker) {
$this->marker = $marker;
}
public function mark($param) {
return $this->marker->mark($param);
}
}
class Add extends Question{
//其他方法
}
abstract class Marker{
abstract function mark($param);
}
class Marker10 extends Marker{
function mark($param) {
return $param + 10;
}
}
class Marker20 extends Marker{
function mark($param) {
return $param + 20;
}
}
$add = new Add(new Marker10());
echo $add->mark(10);//20
$add = new Add(new Marker20());
echo $add->mark(10);//30
2、工厂模式
<?php
/**
* 工厂模式,工厂模式分为工厂方法模式和抽象工厂模式
* 工厂方法模式就是类Factory和Pen,他们下面都有对应
* 的子类,可以"横向"扩展,抽象工厂模式就是两个类联合起来,
* 比如Book类调用了Pencil类,Notebook类调用了ColourPen,实现
* 了"纵向"扩展
*/
abstract class Factory{
public function index() {
echo 'html';
}
abstract public function getPen();
}
class Book extends Factory{
public function getPen() {
return new Pencil();
}
}
class Notebook extends Factory{
public function getPen(){
return new ColourPen();
}
}
abstract class Pen{
}
class Pencil extends Pen{
}
class ColourPen extends Pen{
}
3、原型模式
<?php
/**
* 原型模式,原型模式类似抽象工厂模式
*/
class Book{
private $pen;
public function __construct(Pen $pen) {
$this->pen = $pen;
}
public function getPen() {
return clone $this->pen;
}
}
abstract class Pen{}
class Pencil extends Pen{}
class ColourPen extends Pen{}
4、组合模式
<?php
/**
* 组合模式,可以把任何形式组合起来
*/
abstract class Group{
private $groups = array();
public function add(Group $group) {
$this->groups[] = $group;
}
public function remove(Group $group) {
$this->groups = array_diff(array($group),$this->groups);
}
public function money() {
$count = 0;
foreach ($this->groups as $group) {
$count += $group->money();
}
return $count;
}
}
class Buy extends Group{
}
class Pen extends Group{
public function money() {
return 10;
}
}
class Book extends Group{
public function money() {
return 12;
}
}
$buy = new Buy();
$buy->add(new Pen());
$buy->add(new Book());
//声明一个新的Buy对象
$buy2 = new Buy();
//把$buy添加进来
$buy2->add($buy);
$buy2->add(new Book());
echo $buy2->money(); //34
5、装饰模式
<?php
/**
* 策略模式,和组合模式很相似,下面的举例
* 比如工资是100,吃用了10,房子花了90,最后只剩下0
*/
abstract class Money{
abstract function cost();
}
class Salary extends Money{
private $salary = 100;
public function cost() {
return $this->salary;
}
}
abstract class Life extends Money{
protected $salary;
function __construct(Money $money) {
$this->salary = $money;
}
}
class Eat extends Life{
public function cost() {
return $this->salary->cost() - 10;
}
}
class House extends Life{
public function cost() {
return $this->salary->cost() - 90;
}
}
//首先是发工资(new Salary),然后是吃(new Eat),然后是房子(new House)
$salary = new House(new Eat(new Salary()));
echo $salary->cost(); //0
6、策略模式
<?php
/**
* 策略模式,当类中实现了多种实现方式的时候,最好把这些方式
* 提取出来放到自己的类型中,而不是通过继承去支持这些实现,
* 下面的例子是一个计算方式是加10,一个是加20,这样无论有多少
* 中算法都可以无限扩展,问题也可以无线扩展,这样不会有代码冗余
*/
abstract class Question{
protected $marker;
public function __construct(Marker $marker) {
$this->marker = $marker;
}
public function mark($param) {
return $this->marker->mark($param);
}
}
class Add extends Question{
//其他方法
}
abstract class Marker{
abstract function mark($param);
}
class Marker10 extends Marker{
function mark($param) {
return $param + 10;
}
}
class Marker20 extends Marker{
function mark($param) {
return $param + 20;
}
}
$add = new Add(new Marker10());
echo $add->mark(10);//20
$add = new Add(new Marker20());
echo $add->mark(10);//30
7、观察者模式,可以自由组合要处理的观察者
<?php
/**
* 被观察者接口
*/
interface Observable{
/* 添加观察者 */
function attach(Observer $observer);
/* 删除观察者 */
function detach(Observer $observer);
/* 通知观察者操作 */
function notify();
}
/**
* 登录被观察者
*/
class Login implements Observable{
private $status;
private $observers = array();
/* 登录 */
function post() {
//登录是否成功
$this->status = mt_rand(0,1);
//通知观察者
$this->notify();
}
function getStatus() {
return $this->status;
}
/* 添加观察者 */
function attach(Observer $observer) {
$this->observers[] = $observer;
}
/* 删除观察者 */
function detach(Observer $observer) {
$newObservers = array();
foreach ($this->observers as $key => $value) {
if($observer !== $value) {
$newObservers[] = $value;
}
}
$this->observers = $newObservers;
}
/* 通知观察者 */
function notify() {
if($this->observers) {
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
}
}
/**
* 观察者抽象类
*/
abstract class Observer{
function __construct(Observable $observable) {
$observable->attach($this);
}
abstract function update(Observable $observable);
}
/**
* 设置登录成功就写日志
*/
class Log extends Observer{
function update(Observable $observable) {
if($observable->getStatus() == 1) {
echo 'write log';
}
}
}
/**
* 设置登录失败就发送email
*/
class Email extends Observer{
function update(Observable $observable) {
if($observable->getStatus() == 0) {
echo 'Send Email';
}
}
}
$login = new Login();
//可以自由组合登录状态的操作
new Log($login);
new Email($login);
//登录
$login->post();
总结:这里的设计模式不是全部,只是抛砖引玉。设计模式的原则是“组合优于继承,继承优于多台”,当然这里是相对来说的,还需要具体问题具体分析,还有我们什么时候该考虑设计呢——从一开始,没错,写代码之前就要开始设计,在写代码过程中,如果遇到“代码重复”、“类知道的太多”、“万能的类”、“条件语句”的问题,就要考虑要不要设计一下了。