php面向对象及常见设计模式

本文是我在周末复习面向对象编程及常见设计模式时的笔记,比较简陋,并且由于文章篇幅和文件组织结构的问题,相关的代码没有办法在文章中贴出,我把它们放到了自己的 github 上边。另外,在学习过程中,我发现了一个很好的学习文档(书) 图说设计模式,书中使用图形和代码结合的方式来解析设计模式,对于理解和使用设计模式有极大帮助,推荐给大家

spl 提供的四种常用数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 栈
$stack = new SplStack();
$stack->push("s1\n");
$stack->push("s2\n");
echo $stack->pop();
echo $stack->pop();

// 队列
$queue = new SplQueue();
$queue->enqueue("q1\n");
$queue->enqueue("q2\n");
echo $queue->dequeue();
echo $queue->dequeue();

// 堆
$heap = new SplMinHeap();
$heap->insert("h1\n");
$heap->insert("h2\n");
echo $heap->extract();
echo $heap->extract();

// 固定长度的数组
$array = new SplFixedArray(10);
$array[0] = 123;
$array[9] = 1234;
var_dump($array);

链式操作

链式操作很简单,在每个方法中返回当前对象即可

魔术方法

  • _get/_set 接管对象属性
  • _call/_callStatic 控制类对象方法/类静态方法调用
  • _toString 将对象转换成字符串时回调
  • _invoke 将对象当成函数来执行时回调

3 种基本设计模式

  • 工厂模式:工厂方法或者类生成对象,而不是在代码中直接 new
  • 单例模式:使某个类的对象仅允许创建一个
  • 注册模式:全局共享和交换对象

适配器模式

将截然不同的函数接口封装成统一的 API,例如:PHP 的数据库操作有 mysql、mysqli、dbo ,可以使用适配器模式统一成一致的。再比如:使用 cache 适配器将 memcache、redis、file、apc(Alternative PHP Cache) 等不同的缓存函数,统一成一致

策略模式

  • 将一组特定的行为和算法封装成类,以适应某些特定的上下文环境
  • 例如:一个电商网站,针对不同性别的用户展示不同的商品类别和不同的广告
  • 使用策略模式可以实现依赖倒置、控制反转

数据对象映射模式

将对象和数据存储映射起来,对一个对象的操作会映射成对数据存储的操作

观察者模式

  • 当一个对象状态发生改变时,依赖它的对象全部会收到通知,并自动更新
  • 一个事件发生后,要执行一连串更新操作,传统的方式,是在事件之后的代码中直接添加处理逻辑
  • 当更新的逻辑增多之后,代码会变得难以维护
  • 这种方式是耦合的、侵入式的
  • 观察者模式实现低耦合、非侵入式的通知与更新机制

原型模式

  • 与工厂模式作用类似,都是用来创建对象的
  • 与工厂模式实现不同,原型模式是先创建好一个原型对象,然后通过 clone 原型对象来创建新的对象
  • 这样就免去了类创建时重复的初始化操作
  • 原型模式适用于大对象创建,创建大对象需要很大的开销,如果每次 new 就会消耗很大,原型模式仅需内存拷贝即可

装饰器模式

  • 可以动态添加修改类的功能
  • 一个类提供了一项功能,如果要修改并添加额外的功能,传统编程模式,需要写一个子类来继承它,并重新实现类的方法
  • 使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大灵活性

迭代器模式

  • 在不需要了解内部实现的前提下,遍历一个聚合对象的内部元素
  • 相比传统编程模式,迭代器模式可以隐藏遍历元素所需的操作

代理模式

  • 在客户端和实体之间建立一个代理对象(proxy),客户端对实体进行的操作全部委派给代理对象,隐藏实体的具体实现细节
  • mysql 主从结构,使用代理模式,业务代码不需要什么修改,就可以实现一个读写分离
  • proxy 还可以与业务代码分离,部署到另外的服务器。业务代码中通过 RPC(远程过程调用)来委派任务

面向对象编程的基本原则

  • 单一职责:一个类,只需要做好一件事情
  • 开放封闭:一个类,应该是可扩展的,而不可修改的
  • 依赖倒置:一个类,不应该强依赖另外一个类,每个类对于另外一个类都是可替换的
  • 配置化:尽可能地使用配置,而不是硬编码
  • 面向接口编程:只需关心接口,不需要关心实现