OOP设计模式 - 创建型

没有银弹!! 设计模式只是特定情况下解决问题的一种推荐方案,但世界上没有完美的方案,不要为了设计模式而设计模式。

Posted by 昆山吴彦祖 on 2021.12.28

最近离职在家,开始规划职业后期发展,虽然大多数情况下php程序员都是curd工程师,but我们自己不能没有追求啊。 人如果没有梦想,那和咸鱼有什么区别? 不管是继续做开发亦或者往架构师方向发展,设计模式都是进阶的必修课。

SO 这几天重新看了下设计模式,纸上得来终觉浅,绝知此事要躬行。 所以自己根据自己的理解写一些案例加深下印象和理解

最后,没有银弹!! 设计模式只是特定情况下解决问题的一种推荐方案,但世界上没有完美的方案,不要为了设计模式而设计模式。

试着去理解很重要,当我们在代码开发过程中,经常会有种微妙的违和感,感觉不太对。这时候我们就需要考虑下 ,是不是代码存在不合理或者不完美的地方,是不是可以通过设计模式来优化。

  1. 简单工厂
  2. 工厂方法模式
  3. 抽象工厂模式
  4. 建造者模式
  5. 单例模式
  6. 多例模式
  7. 原型模式
  8. 对象池模式

创建型 - 故名思意,这些设计模式主要解决的问题就是如何更好的创建对象,所谓更好的意思,大概就是更符合我们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');
	}
}

设计模式