面向对象(Object-Oriented Programming, OOP)
特征
- 封装
- 继承
- 多态
面向对象设计五大原则
单一职责原则(Single Pesponsibility Principle, SRP)
- 一个类只需要做好一件事情
接口隔离原则(Interface Segregation Principle,ISP)
- 一个类对另外一个类的依赖性应当是建立在最小接口上的
开放-封闭原则(Open-Close Principle, OCP)
- 一个类是可以扩展的,而不可修改的
替换原则(Liskov Substitution Principle, LSP)
- 替换原则也称里氏替换原则
- 子类型必须能够替换掉它们的父类型,并出现在父类能够出现的任何地方
- 父类的方法都要在子类中实现或重写,并且派生类只实现其抽象类中声明的方法,而不应当给出多余的方法定义或实现
依赖倒置原则(Dependence Inversion Principle, DIP)
- 一个类不应该强依赖于另外一个类,每个类对于另外一个类都是可以替换的
PHP常用设计模式
工厂模式
工厂方法或者类生成对象,而不是在代码中直接new
应用场景:
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
Factory::createDatabase();
class Factory{
static function createDatabase(){
$db = new Database();
return $db;
}
}
单例模式
使某个类的对象仅允许创建一次
应用场景:
程序应用中,涉及到数据库操作时,如果每次操作的时候连接数据库,会带来大量的资源消耗。可以通过单例模式,创建唯一的数据库连接对象。
$db = Database::getInstance();
class Database{
protected $db;
private function __construct(){
}
static function getInstance(){
if(!self::$db){
self::$db = new self();
}
return self::$db;
}
}
工厂模式+单例模式
//工厂模式
Factory::createDatabase();
class Factory{
static function createDatabase(){
//单例模式
$db = Database::getInstance();
return $db;
}
}
class Database{
protected $db;
private function __construct(){
}
static function getInstance(){
if(self::$db){
return self::$db;
}else{
self::$db = new self();
return self::$db;
}
}
}
注册模式
解决全局共享和交换条件
将类的对象注册到全局类上,在需要使用的时候可以直接访问
//定义一个空对象,模拟实例
$single = (object)[];
//将实例$single注册到数组中
Register::set("single", $single);
//获取该实例
$obj = Register::get("single");
class Register{
protected static $objects;
static function set($alias, $object){
self::$objects[$alias] = $objects;
}
static function get($name){
return self::$objects[$alias];
}
function _unset($alias){
unset(self::$objects[$alias]);
}
}
适配器模式
将各种截然不同的函数接口封装成统一的API
应用场景:
PHP中的数据库操作有MySQL,MySQLi,PDO三种,可以用适配器模式统一成一致,使不同的数据库操作,统一成一样的API
//声明接口,约定了统一api的方式,适配器都有哪些行为
//分别创建每个适配器的实例,必须继承至这个接口,必须实现这些接口所约定的所有方法
$db = new Mysql();
$db->connect('127.0.0.1', 'root', 'root', 'test');
$db->query('show databases');
$db->close();
interface IDatabase{
function connect($host, $user, $password, $dbname);
function query($sql);
function close();
}
class Mysql implements IDatabase{
protected $connect;
function connect($host, $user, $password, $dbname){
$connect = mysql_connect($host, $user, $password);
mysql_select_db($dbname, $connect);
$this->connect = $connect;
}
function query($sql){
$res = mysql_query($sql, $this->connect);
return $res
}
function close(){
mysql_close($this->connect);
}
}
class Mysqli implements IDatabase{
protected $connect;
function connect($host, $user, $password, $dbname){
$connect = mysqli_connect($host, $user, $password, $connect);
$this->connect = $connect;
}
function query($sql){
$res = mysqli_query($this->connect, $sql);
return $res
}
function close(){
mysqli_close($this->connect);
}
}
class Pdo implements IDatabase{
protected $connect;
function connect($host, $user, $password, $dbname){
$connect = new \PDO("mysql:host=$host;dbname=$dbname", $user, $password);
$this->connect = $connect;
}
function query($sql){
return $this->connect->query($sql);
}
function close(){
unset($this->connect);
}
}
策略模式
将一组特定的行为和算法封装成类,以适应某些特定的上下文环境
应用场景:
假如一个电商网站系统,针对男女用户要各自跳转到不同的商品类目,并且所有的广告位展示不同的广告
class Page{
protected $UserStrategy;
function index(){
$this->UserStrategy->showCategory();
}
function setStrategy(UserStrategy $UserStrategy){
$this->UserStrategy = $UserStrategy;
}
}
$page = new Page();
if(isset($_GET['female'])){
$UserStrategy = new FemaleUserStrategy();
}else{
$UserStrategy = new MaleUserStrategy();
}
$page->setStrategy($UserStrategy)
$page->index();
//两种策略 一种针对男性,一种针对女性
class MaleUserStrategy implements UserStrategy{
function showAd(){
echo '男装服饰';
}
function showCategory(){
echo '男装';
}
}
class FemaleUserStrategy implements UserStrategy{
function showAd(){
echo '女装服饰';
}
function showCategory(){
echo '女装';
}
}
interface UserStrategy{
function showAd();
function showCategory();
}
数据对象映射模式
将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作
应用场景:
实现一个ORM类,将复杂的sql语句映射成对象属性的操作,结合使用数据对象映射模式、工厂模式、注册模式
class User{
public $id;
public $name;
public $mobile;
public $regtime;
protected $db;
function __construct($id){
$this->db = new Mysqli();
$this->db->connect('127.0.0.1', 'root', 'root', 'test');
$res = $this->db->query('select * from user limit');
$data = $res->fetch_assoc();
$this->id = $data['id'];
$this->name= $data['name'];
$this->mobile = $data['mobile'];
$this->regtime = $data['regtime'];
}
function __destruct(){
$this->db->query("update user set name = '{$this->name}' where id = '{$this->id}'");
}
}
$user = new User(1);
$user->mobile = '17859902536';
$user->name = 'username'
$user->regtime = time();
观察者模式
观察者模式(Observer),当一个对象状态发生变化时,依赖它的对象全部会收到通知,并自动更新。
应用场景:一个事件发生后,要执行一连串的更新。传统的编程方式就是在事件的代码之后直接加入处理逻辑。当更新的逻辑增加之后,代码会变得难以维护,这种方法是耦合的,侵入式的,增加新的逻辑需要修改事件主体的代码。观察者模式实现了低耦合,非侵入式的通知与更新机制。
php链式操作的实现,调用的每个方法:return $this;
$Event = new Event();
$Event->addObserver(new Observer1);
$Event->addObserver(new Observer2);
$Event->trigger();
class Event extends EventGenerator{
function trigger(){
echo "Event";
$this->notify();
}
}
//抽象类
abstract class EventGenerator{
private $Observers = array();
function addObserver(Observer $Observer){
$this->Observers[] = $Observer;
}
function notify(){
foreach($this->Observers as $Observer){
$Observer->update();
}
}
}
class Observer1 implements Observer{
function update($event_info = null){
echo '逻辑1';
}
}
class Observer2 implements Observer{
function update($event_info = null){
echo '逻辑2';
}
}
interface Observer{
function update($event_info = null);
}
原型模式
与工厂模式作用类似,都是用来创建对象
与工厂模式的实现不同,原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。这样就免去了类创建时重复的初始化操作
原型模式适用于大对象的创建,创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需内存拷贝即可
$prototype = new Canvas();
$prototype->init();
//原型模式
$Canvas1 = clone $prototype;
$Canvas2 = clone $prototype;
装饰器模式
可以动态的添加修改类的功能
一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重新实现类的方法
使用装饰器模式,仅需要在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性
$canvas1 = new Canvas();
$canvas1->init();
$canvas1->addDecorator(new ColorDrawDecorator('green'));
$canvas1->addDecorator(new SizeDrawDecorator('16'));
$canvas1->draw();
interface DrawDecorator{
function beforeDraw();
function afterDraw();
}
class SizeDrawDecorator implements DrawDecorator{
protected $size;
function __construct($size = '14'){
$this->size = $size;
}
function beforeDraw(){
//todo
}
function afterDraw(){
//todo
}
}
class ColorDrawDecorator implements DrawDecorator{
protected $color;
function __construct($color = 'red'){
$this->color = $color;
}
function beforeDraw(){
//todo
}
function afterDraw(){
//todo
}
}
class Canvas{
protected $DrawDecorators = array();
function addDecorator(DrawDecorator $DrawDecorator){
$this->DrawDecorators[] = $DrawDecorator;
}
function beforeDraw(){
foreach($this->DrawDecorators as $DrawDecorator){
$DrawDecorator->beforeDraw();
}
}
function afterDraw(){
$DrawDecorators = array_reverse($this->DrawDecorators);
foreach($DrawDecorators as $DrawDecorator){
$DrawDecorator->afterDraw();
}
}
function draw(){
$this->beforeDraw();
//todo 中间代码
$this->afterDraw();
}
}
迭代器模式
不需要了解内部实现的前提下,遍历一个聚合对象的内部元素
相对于传统的编程模式,迭代器模式可以隐藏遍历元素的所需的操作
代理模式
在客户端与实体之间建立一个代理对象,客户端对实体进行操作全部委派给代理对象,隐藏实体的具体的实现细节
代理还可以与业务代码分离,部署到另外的服务器,业务中通过RPC来委派任务(数据库主从分离)
$Proxy = new Proxy();
$Proxy->getUserName($id);
$Proxy->setUserName($id, $username);
class IUserProxy{
function getUserName($id);
function setUserName($id, $username);
}
class Proxy implements IUserProxy{
function getUserName($id){
$db = Factory::getDatabase('slave');
$db->query();
}
function setUserName($id, $username){
$db = Factory::getDatabase('master');
$db->update();
}
}