最近离职在家,开始规划职业后期发展,虽然大多数情况下php程序员都是curd工程师,but我们自己不能没有追求啊。 人如果没有梦想,那和咸鱼有什么区别? 不管是继续做开发亦或者往架构师方向发展,设计模式都是进阶的必修课。
SO 这几天重新看了下设计模式,纸上得来终觉浅,绝知此事要躬行。 所以自己根据自己的理解写一些案例加深下印象和理解
最后,没有银弹!! 设计模式只是特定情况下解决问题的一种推荐方案,但世界上没有完美的方案,不要为了设计模式而设计模式。
试着去理解很重要,当我们在代码开发过程中,经常会有种微妙的违和感,感觉不太对。这时候我们就需要考虑下 ,是不是代码存在不合理或者不完美的地方,是不是可以通过设计模式来优化。
创建型 - 故名思意,这些设计模式主要解决的问题就是如何更好的创建对象,所谓更好的意思,大概就是更符合我们OOP开发中的几大基本思想:单一职责、李氏替换、依赖反转、开放封闭、接口隔离
简单工厂
最简单的工厂
//工厂类
class Factory(){
public function create($type){
switch($type){
case('car'):
return new Car();
case('bus'):
return new Bus();
}
}
}
//产品接口
interface product(){
public function run();
public function stop();
}
//具体产品
class car implements product(){
public function run(){
echo "car is run very fast";
}
public function stop(){
echo "car is stop";
}
}
//具体产品
class bus implements product(){
public function run(){
echo "bus is run slowly";
}
public function stop(){
echo "bus is stop";
}
}
//使用
$factory = new Factory();
$mycar = $factory->create("car");
$mycar->run();
$mycar->stop();
工厂方法模式
简单工厂的升级版,因为简单工厂把所有产品创造的细节都耦合在工厂内部实现。
每次新增产品就得更改工厂,对于开闭原则上而言,还是有待改进的。
//抽象工厂
abstract class Factory(){
abstract public function create();
}
//具体工厂
class CarFactory extends Factory(){
public function create(){
return new Car();
}
}
//具体工厂
class BusFactory extends Factory(){
public function create(){
return new Bus();
}
}
//产品接口
interface product(){
public function run();
public function stop();
}
//具体产品
class car implements product(){
public function run(){
echo "car is run very fast";
}
public function stop(){
echo "car is stop";
}
}
class bus implements product(){
public function run(){
echo "bus is run slowly";
}
public function stop(){
echo "bus is stop";
}
}
//使用
$factory = new CarFactory();
$mycar = $factory->create("car");
$mycar->run();
$mycar->stop();
抽象工厂模式
工厂方法虽然更符合封闭原则,每次有新的产品不需要在改动工厂本身,而是用拓展新工厂来代替。
但是,当产品多样化后,产品具有比较多维的结构关系,这时候:
1、每个产品只能对应一个工厂说实话效率并不高,我们更希望工厂是个能生产多样化产品的工厂(多条不同产品流水线)
2、产品本身之间存在的联系我们希望保留并在创造的时候得以体现,也是所谓的产品族概念(奔驰公司除了生成汽车,可能还生产跑车、巴士等等,但他们都属于奔驰公司产品,通过同一个工厂生产某种程度上更方便做产品的一些设定)
抽象工厂应运而生,抽象工厂更像我们现实中的工厂,可以同时生产不同种类的产品,但生产的产品具有某些共同属性或方法;相比较而言,工厂方法更像是一条生产线,只能生成固定的某个产品。
//抽象工厂
abstract class Factory(){
abstract public function createCar();
abstract public function createBus();
}
//具体工厂
class BenzFactory extends Factory(){
private $brand = "Benz";
public function createCar($name,$type){
return new BenzCar($name,$type,$this->brand);
}
public function createBus($name){
return new BenzBus($name,$this->type);
}
}
//具体工厂
class BmwFactory extends Factory(){
private $brand = "Bmw";
public function createCar($name,$type){
return new BmwCar($name,$type,$this->brand);
}
public function createBus($name){
return new BmwBus($name,$this->type);
}
}
//产品接口
interface Product(){
public function run();
public function stop();
}
//抽象工厂通常有多个抽象产品 - 每个抽象工厂为多种产品提供生产线
abstruct Car implements Product(){
public $name;
public $brand;
public $type;
public function __construct($name,$type,$brand){
$this->name = $name;
$this->type = $type;
$this->brand= $brand;
}
abstruct public function run();
abstruct public function stop();
abstruct public function myfunction_car_a();
abstruct public function myfunction_car_b();
}
abstruct Bus implements Product(){
public $name;
public $brand;
public function __construct($name,$type){
$this->name = $name;
$this->type = $type;
}
abstruct public function run();
abstruct public function stop();
abstruct public function myfunction_bus_a();
}
//具体产品
class Benz_car extends Car(){
public function run(){
echo "$this->type - $this->name is run very fast";
}
public function stop(){
echo "$this->type - $this->name is stop";
}
public function myfunction_car_a(){
echo "function a just for car";
}
public function myfunction_car_b(){
echo "function b just for car";
}
}
class Benz_bus extends Bus(){
public function run(){
echo "$this->name is a bus, so is run very slowly";
}
public function stop(){
echo "$this->name is stop";
}
public function myfunction_bus_a(){
echo "function a just for bus";
}
}
class Bmw_car extends Car(){
public function run(){
echo "$this->type - $this->name is run very fast";
}
public function stop(){
echo "$this->type - $this->name is stop";
}
public function myfunction_car_a(){
echo "function a just for car";
}
public function myfunction_car_b(){
echo "function b just for car";
}
}
//使用
$factory = new BenzFactory();
$mycar = $factory->create("X310","轿跑系列");
$mycar->run();
$mycar->stop();
建造者模式
建造者模式,和工厂模式对比,对大的区别在于 建造者模式更关注创建细节和步骤,工厂关注创建结果。
//通常由一个建造者接口和多个建造者组成
interface Builder(){
public function CreateProduct();
public function AddWheel();
public function AddDoor();
public function AddEngine();
public function Painting();
public function GetProduct():Product;
}
class CarBuilder implements Builder{
public $car;
public function CreateProduct($name){
$this->car = new Car($name);
}
// 因为汽车创建者的细节实现和巴士不同,才有必要分2个创建者
public function AddWheel($wheel){
$this->car->add($wheel,4);
}
public function AddDoor($door){
$this->car->add($door);
}
public function AddEngine($engine){
$this->car->add($engine);
}
public function Painting(){
$this->car->painting();
}
public function GetProduct(){
$this->car;
}
}
class BusBuilder implements Builder{
public $bus;
public function CreateProduct($name){
$this->bus = new Bus($name);
}
public function AddWheel($wheel){
$this->bus->add($wheel,8);
}
public function AddDoor($door_before,$door_after){
$this->bus->add($door_before);
$this->bus->add($door_after);
}
public function AddEngine($engine){
$this->bus->add($engine);
}
public function Painting(){
$this->bus->painting();
}
public function GetProduct(){
$this->bus;
}
}
//产品接口
abstract Product(){
public $parts=[];
public $name;
public $painting = false;
abstract public function run();
abstract public function stop();
public function __construct($name){
$this->name = $name;
}
public function add($part,$number = 1){
for($i=0;$i<$number;$i++){
$this->parts[] = $part;
}
}
public function painting(){
$this->painting = true;
}
}
//具体产品
class Car implements Product(){
public function run(){
echo "car is run very fast";
}
public function stop(){
echo "car is stop";
}
}
class Bus implements Product(){
public function run(){
echo "bus is run slowly";
}
public function stop(){
echo "bus is stop";
}
}
//导演角色 - 对创建者的进一步封装,主要就是为了方便客户端使用建造者,不然我们得在客户端每次执行一整遍建造者的细节。
public Director(){
private $bulider;
public function __construct(Bulider $bulider){
$this->bulider = $builder;
}
public function bulider($name,$door,$wheel,$engine){
$this->bulider->CreateProduct($name);
$this->bulider->AddDoor($door);
$this->bulider->AddEngine($wheel);
$this->bulider->Painting($engine);
return $this->bulider->GetProduct();
}
}
//应用
$builder = new Director(new CarBuilder());
$my_car = $builder->bulider("benz_310","my_door","big_wheel","my_engine");
$my_car->run();
单例模式
单例是个很简单又实用的模式,主要为了节约资源而用,一个类实例化了全局就可以使用。主要用在一些全局组件上比如 数据库连接、session处理器等等
but 看到越来越多的人把单例归为反模式,因为单例本身在实例内部实现了所有功能,所以和我们OOP的种种中心思想是有所偏离,不适合通过 继承和多态实现拓展。但是事实上单例很少会涉及到后期的拓展修改。所以单例还是很不错的一种模式,用的时候要谨慎一点就对了
class Singleton(){
private static $instance;
// 固定为 私有静态
private static function getInstance(){
if(static::instance === null){
static::instance = new self();
}
return static::instance;
}
private function __construct(){
}
private function __clone(){
}
private function __wakeup(){
}
}
//应用
$singleton = Singleton::getInstance();
多例模式
单例模式对于类每次只能创建一个实例,某些状况下我们可能需要多个实例对象,比如数据库连接需要两个 一个做读一个做写。
class Singleton(){
private static $instance = [];
// 固定为 私有静态
private static function getInstance($name){
if(!isset(static::instance[$name])){
static::instance = new self($name);
}
return static::instance[$name];
}
private function __construct($name){
}
private function __clone(){
}
private function __wakeup(){
}
}
//应用
$singleton = Singleton::getInstance('db_write');
原型模式
原型模式的特点就是通过克隆原型来创建新实例。
可能会用到的场景是:
1 、需要创建某个实例的快照用于变更后数据对比
2、某个类型实例需要反复创建,但是每个实例大部分属性都相同
class Bmw_X5{
public $brand = "Bmw";
public $name = "X5";
public $owner ;
public function buy(User $buyer){
$this->owner = $buyer;
}
public function __clone(){}
}
//应用
$X5 = new Bmw_X5();
$user = new User("张三");
$X5_1 = clone $X5;
$X5_1->buy($user);
对象池模式
对象池主要用于一些每次创建都需要消耗资源的实例,比如数据库连接、redis连接、tcp连接池等, 经常会配合单例使用。
class pool(){
public $pool=[];
public $size;
public function __construct($size){
for($i=0;$i<$size;$i++){
self::make();
}
}
// 核心的两个方法,从池子获取和归还池子
// 归还不是必须的,只有当池子里装载的是同时只给1个进程使用的资源时才需要做归还动作,比如数据库连接、套接字
public function get(){
$connect = array_pop($this->pool);
if($connect){
return $connect;
}else{
throw new \\Exception("没有可用的连接");
}
}
public function put($connect){
$this->pool[] = $connect;
}
private function make(){
$this->pool[] = new PDO("mysql:host=localhost;dbname=demo;charset=utf8",'root','root');
}
}