六大原则与设计模式
1. 六大原则
1.1 单一原则(SRP)
应该有且仅有一个原因引起类的变更
1. 复杂性降低,可读性高,可维护性提高
2. 变更引起的风险降低,变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。
class a{
public function info(){
echo "第一条消息";
}
}
class b{
public function text(){
echo "第二条消息";
}
}
class c {
public function run(){
$a = new a();
$a->info();
$b = new b();
$b->text();
}
}
$c = new c();
$c->run();
1.2 开闭原则
类应该对扩展开放,对修改关闭
interface A{
public function boot();
}
class B implements A{
public function boot(){
return rand(1,100);
}
}
class cli{
public function run(){
$b= new B();
return $b->boot();
}
}
$cli = new cli();
echo $cli->run();
1.3 里氏替换原则
子类必须能够替换掉它们的基类
class A{
public function a(){
return "电子产品";
}
}
class B extends A{
public function a()
{
return "手机";
}
}
class client
{
public function run()
{
$b = new B();
echo $b->a();
}
}
$client = new client();
$client->run();
1.4 依赖倒置原则
高层模块不应该依赖于低层模块,它们都应该依赖于抽象。
interface A{
public function str();
}
class B implements A{
public function str()
{
return rand(1,100);
}
}
class C implements A{
public function str()
{
return "123";
}
}
1.5 接口隔离原则 (ISP)
类不应该依赖于它不需要的接口
interface A{
public function a();
public function b();
}
class B implements A{
public function a()
{
return "a";
}
public function b()
{
return "b";
}
}
1.6 迪米特法则
优先使用对象组合而不是类继承
class a{ protected $user; public function __construct(\think\App $app) { $this->user=$app; } public function index($id){ return $this->user->index($id); } }
这些原则有助于写出高内聚、低耦合的代码,使得代码更易于维护和扩展。
2. 设计模式
2.1 结构型模式
2.1.1 装饰器模式
装饰器模式用于动态地将新的行为添加到对象上,对于需要扩展功能的类来说是一种更加灵活的设计方案。在PHP中,可以使用装饰器模式来为已有的对象添加新的行为,不需要修改已有类的代码。
装饰器的优点:
1. 不改变代码的情况下对原代码的功能职责进行扩展,遵守了开闭原则
2. 每个类都有属于自己的功能职责
interface MobileCase
{
public function boot();
}
class Mobile implements MobileCase
{
public function boot()
{
echo "无色无图案手机壳".PHP_EOL;
}
}
abstract class MobileDecorator implements MobileCase
{
protected $mobileCase;
public function __construct(MobileCase $mobileCase)
{
$this->mobileCase = $mobileCase;
}
public function boot()
{
$this->mobileCase->boot();
}
}
class HedMobileCase extends MobileDecorator
{
private $name = "红色手机壳";
private function add()
{
echo $this->name.PHP_EOL;
}
public function boot()
{
$this->mobileCase->boot();
$this->add();
}
}
class GreenMobileCase extends MobileDecorator
{
private $name = "黄色手机壳";
private function add()
{
echo $this->name.PHP_EOL;
}
public function boot()
{
$this->mobileCase->boot();
$this->add();
}
}
class client
{
public function run()
{
$MobileCase = new Mobile();
$HedMobileCase = new HedMobileCase($MobileCase);
$HedMobileCase->boot();
}
}
$client = new client();
$client->run();
2.1.2 facade门面模式
又称为外观模式,为子系统中的一组接口提供一个统一的高层接口, 使得子系统更容易使用
门面模式的组成:
1. 外观角色 :模式的核心,被客户 Client 调用,知道各个子系统的概念。
2. 子系统角色 :实现子系统的功能。
3. 客户角色 :调用 Facade 角色获取相应的功能。
门面模式的优缺点:
1. 降低系统的复杂程度 2. 低耦合 3. 使用简单 4. 可能违背开闭原则
class Connection
{
private function conn()
{
try {
$connection = new PDO('mysql:host=127.0.0.1;dbname=starsky','root','root');
return $connection;
}catch (PDOException $exception){
echo $exception->getMessage();
}
}
public function run()
{
return $this->conn();
}
}
class DBQuery
{
public function query(Connection $connection,$sql)
{
try {
$pdo = $connection->run();
$restful = $pdo->query($sql)->fetchAll();
return $restful;
}catch (PDOException $exception){
echo $exception->getMessage();
}
}
}
class facade
{
private $query;
private $conn;
public function __construct()
{
$this->query = new DBQuery();
$this->conn = new Connection();
}
public function select($sql)
{
return $this->query->query($this->conn,$sql);
}
}
class DB
{
private static $query;
public static function select($sql)
{
static::$query = new facade();
return self::$query->select($sql);
}
}
var_dump(DB::select('select * from `user`'));
2.1.3 注册树模式
通过将对象实例注册到一棵全局的对象树上,需要的时候从对 象树上采摘的模式设计方法
1. Laravel框架的服务容器 2. Thinkphp框架
class Container
{
private $bindings = [];
public function bind($abstract, $concrete = null, $shared = false)
{
$this->bindings[$abstract]['concrete'] = $concrete;
$this->bindings[$abstract]['shared'] = $shared;
}
public function make($abstract,$parameters = [])
{
$object = $this->bindings[$abstract]['concrete'];
if ($object instanceof \Closure){
return $object();
}
if (!is_object($object)){
$object = new $object(...$parameters);
}
return $object;
}
public function delete($abstract)
{
unset($this->bindings[$abstract]);
}
}
class A
{
public function run()
{
echo "这里是A类的run方法";
}
}
$container = new Container();
$container->bind('a',new A());
$container->make('a')->run();
class Container
{
//用于存储实例化的对象或者类的命名空间
private $bindings = [];
//注册对象到$bindings数组里面,进行存储
public function bind($abstract, $concrete = null)
{
$this->bindings[$abstract] = $concrete;
}
}
class A{
}
$container = new Container();
$container->bind('A',new A());
interface I
{
public function boot();
}
/**
* Class A php项目生成的数据 => 给java语言接口
*/
class A implements I
{
public function boot()
{
$data = ["id" =>1,"name" => "starsky"];
return json_encode($data);
}
}
/**
* Class B java生成的数据 =>php语言接口
*/
class B implements I
{
public function boot()
{
$data = ["id" =>1,"name" => "starsky"];
return serialize($data);
}
}
interface I_Apadtor
{
public function boot(I $i);
}
class Apadtor implements I_Apadtor
{
public function boot(I $i)
{
if (!is_null($string = json_decode($i->boot()))){
return serialize($string);
}else{
$string = unserialize($i->boot());
return json_encode($string);
}
}
}
$Apadtor = new Apadtor();
//java端调用php端数据
var_dump("java调用php的数据:".$Apadtor->boot(new A()));
//php端调用java端数据
var_dump("php调用java的数据:".$Apadtor->boot(new B()));
2.1.4 适配器模式
将一个类的接口,转换成客户期望的另一个类的接口。适配器让原 本接口不兼容的类可以合作无间。
interface I
{
public function boot();
}
class A implements I
{
public function boot()
{
$data = ["name" => "starsky","age" => 100,"sex" => 1];
return serialize($data);
}
}
class B implements I
{
public function boot()
{
$data = ["name" => "starsky","age" => 100,"sex" => 1];
return json_encode($data);
}
}
interface I_Adaptor
{
public function boot(I $i);
}
class Adaptor implements I_Adaptor
{
public function boot(I $in)
{
if (!is_null($string = json_decode($in->boot()))){
return serialize($string);
}else{
$string = unserialize($in->boot());
return json_encode($string);
}
}
}
$Adaptor = new Adaptor();
var_dump(json_decode($Adaptor->boot((new A()))));
var_dump(unserialize($Adaptor->boot((new B ()))));
2.1.5 Pipeline模式
应用场景: 1.订单生成 2.Laravel中中间件的执行
class A
{
public static function handle($request)
{
echo "这里A类的Boot方法".PHP_EOL;
}
}
class B
{
public static function handle($request)
{
echo "这里是B类的Boot方法".PHP_EOL;
}
}
class C
{
public static function handle($request)
{
echo "这里是C类的Index方法".PHP_EOL;
}
}
class D
{
public function index()
{
echo "这里是D类的index方法";
}
}
interface PipelineInterface
{
public function pipe($middleware);
public function then();
}
class Pipeline implements PipelineInterface
{
protected $Middleware = [];
protected $request;
public function __construct($object,$method,$argv = [])
{
$this->request['object'] = $object;
$this->request['method'] = $method;
$this->request['argv'] = $argv;
}
public function pipe($middleware)
{
$this->Middleware = $middleware;
return $this;
}
public function then()
{
foreach ($this->Middleware as $value){
call_user_func([$value,'handle'],$this->request);
}
return $this;
}
public function send()
{
$method = $this->request['method'];
return $this->request['object']->$method(...$this->request['argv']);
}
}
class Kernel
{
protected $Middleware = [];
public function handle(Pipeline $pipeline)
{
return $pipeline->pipe($this->Middleware)
->then()
->send();
}
}
class Http extends Kernel
{
protected $Middleware=[
A::class,
B::class,
C::class
];
}
$httpKernel = (new Http())->handle(new Pipeline(new D(),'index'));
2.1.6 代理模式
给某一个对象提供一个代理,并由代理对象控制对原对象的引用
interface I
{
public function boot();
public function handle();
}
class A implements I
{
public function boot()
{
echo "A类的boot方法".PHP_EOL;
}
public function handle()
{
echo "A类的handle方法".PHP_EOL;
}
}
class Proxy implements I
{
protected $A;
public function __construct(I $i)
{
$this->A = $i;
}
public function boot()
{
$this->A->boot();
}
public function handle()
{
$this->A->handle();
}
}
$Proxy = new Proxy(new A());
$Proxy->boot();
$Proxy->handle();
2.2 创建型模式
2.2.1 简单工厂模式
简单工厂的作用是实例化对象,而不需要客户了解这个对象属于哪个具体的子类。
//mysql报错日志
class MysqlLog
{
}
//Redis报错日志
class RedisLog
{
}
//用户操作错误日志
class UserLog
{
}
//代码错诶日志
class ErrorLog
{
}
class Product
{
protected $Log;
public function __construct(array $modules)
{
$factory = new LogFactory();
foreach ($modules as $module){
$this->Log[$module] = $factory->make($module);
}
}
public function getLog()
{
return $this->Log;
}
}
class LogFactory
{
public function make($abstract)
{
switch ($abstract){
case 'mysql':
return new MysqlLog();
case 'redis':
return new RedisLog();
case 'user':
return new UserLog();
case 'error':
return new ErrorLog();
}
}
}
$Product = new Product(array(
'mysql',
'redis',
'user',
'error'
));
var_dump($Product->getLog());
2.2.2 Factory工厂模式
简单工厂模式的延伸,是在简单工厂的优点上去解决它的缺陷
方法工厂模式的优点: 1.拥有良好的封装性,代码结构清晰 2. 拥有良好的扩展性 3. 屏蔽产品类
使用场景: 1. 日志记录 2. 多接口支付 3. 数据库连接封装
interface LogInterface
{
public function log();
}
//mysql报错日志
class MysqlLog implements LogInterface
{
public function log()
{
// TODO: Implement log() method.
}
}
//Redis报错日志
class RedisLog implements LogInterface
{
public function log()
{
// TODO: Implement log() method.
}
}
//用户操作错误日志
class UserLog implements LogInterface
{
public function log()
{
// TODO: Implement log() method.
}
}
//代码错诶日志
class ErrorLog implements LogInterface
{
public function log()
{
// TODO: Implement log() method.
}
}
class Product
{
protected $Log;
public function __construct()
{
$this->Log = array(
(new MysqlLogFactory())->make(),
(new RedisLogFactory())->make(),
(new UserLogFactory())->make(),
(new ErrorLogFactory())->make()
);
}
public function getLog()
{
return $this->Log;
}
}
interface LogFactory
{
public function make();
}
class MysqlLogFactory implements LogFactory
{
public function make()
{
return new MysqlLog();
}
}
class RedisLogFactory implements LogFactory
{
public function make()
{
return new RedisLog();
}
}
class UserLogFactory implements LogFactory
{
public function make()
{
return new UserLog();
}
}
class ErrorLogFactory implements LogFactory
{
public function make()
{
return new ErrorLog();
}
}
$product = new Product();
var_dump($product->getLog());
2.2.3 抽象工厂模式
给客户端提供一个接口,可以创建多个产品族中的产品对象
抽象工厂模式的优缺点: 1. 分离了具体的实现类 2. 增加替换工厂类目变的方便 3. 有利于统一同一类型的类目
interface PayInterface
{
public function pay();
}
class AliPay implements PayInterface
{
public function pay()
{
return "支付宝支付";
}
}
class TenPay implements PayInterface
{
public function pay()
{
return "微信支付";
}
}
interface LogInterface
{
public function log();
}
class MysqlLog implements LogInterface
{
public function log()
{
return "记录mysql日志";
}
}
class RedisLog implements LogInterface
{
public function log()
{
return "记录Redis日志";
}
}
interface PayFactoryInterface
{
public function AliPayMake();
public function TenPayMake();
}
interface LogFactoryInterface
{
public function MysqlLogMake();
public function RedisLogMake();
}
class PayFactory implements PayFactoryInterface
{
public function AliPayMake()
{
return new AliPay();
}
public function TenPayMake()
{
return new TenPay();
}
}
class LogFactory implements LogFactoryInterface
{
public function MysqlLogMake()
{
return new MysqlLog();
}
public function RedisLogMake()
{
return new RedisLog();
}
}
class Order
{
protected $log;
protected $pay;
public function __construct()
{
$LogFactory = new LogFactory();
$PayFactory = new PayFactory();
$this->log = array(
'mysql' => $LogFactory->MysqlLogMake(),
'redis' => $LogFactory->RedisLogMake()
);
$this->pay = array(
'Ali' => $PayFactory->AliPayMake(),
'Ten' => $PayFactory->TenPayMake()
);
}
public function getLog()
{
return $this->log;
}
public function getPay()
{
return $this->pay;
}
}
$order = new Order();
var_dump($order->getLog());
var_dump($order->getPay());
2.2.4 Single单例模式
保证一个类只有一个实例,并提供一个访问它的全局访问点
使用场景: 1. 数据库连接 2. 日志操作类 3. 请求管理类 4. 配置管理类
class Request
{
private static $request;
protected $method;
protected $uriPath;
private function __construct(){}
private function __clone(){}
public static function getRequest()
{
if (self::$request == null){
self::$request = new Request();
}
self::$request->method = $_SERVER['REQUEST_METHOD'];
self::$request->uriPath= $_SERVER['REQUEST_URI'];
return self::$request;
}
public function getMethod()
{
return $this->method;
}
public function getUriPath()
{
return $this->uriPath;
}
public function isMethod($method):bool
{
return $this->method === strtoupper($method);
}
}
$request = Request::getRequest();
var_dump($request->isMethod('get'));
2.3 行为型模式
2.3.1 策略模式
定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换
策略模式使用的业务场景: 1. 短语发送 2. 多支付接口 3. 日志记录
interface PayInterface
{
public function pay();
}
class AliPay implements PayInterface
{
public function pay()
{
echo "支付宝支付";
}
}
class TenPay implements PayInterface
{
public function pay()
{
echo "微信支付";
}
}
class Pay
{
protected $pay;
public function __construct(PayInterface $pay)
{
$this->pay = $pay;
}
public function getPay()
{
return $this->pay;
}
}
$pay = new Pay(new AliPay());
$pay->getPay()->pay();
2.3.2 Observe观察者模式
多个对象间存在一对多的依赖关系,当一个对象的状态 发生改变时,所有依赖于它的对象都得到通知并被自动更新
观察者模式的使用场景: 1. 订单支付场景 2. 发布订阅类型的功能
观察者模式的优点: 1. 观察者与被观察者依赖于抽象 2. 观察者符合开闭原则,只要符合接口,就能够进行扩展
观察者模式的缺点: 1. 依赖于接口的关系,具备一定的局限性 2. 过多的观察者,代码运行消耗可能会很大
interface OrderPayInterface
{
public function PayEvent($OrderId = null);
}
class OrderPay implements OrderPayInterface
{
public function PayEvent($OrderId = null)
{
echo "订单ID为:{$OrderId}的订单状态为已支付".PHP_EOL;
}
}
abstract class OrderEventAbstract
{
private $Observer;
public function register(OrderPayInterface $pay)
{
$this->Observer = $pay;
}
public function notify($OrderId)
{
$this->Observer->PayEvent($OrderId);
}
}
class Order extends OrderEventAbstract
{
public function pay($OrderId)
{
echo "支付成功".PHP_EOL;
$this->notify($OrderId);
}
}
$order = new Order();
$order->register(new OrderPay());
$order->pay(1);
2.3.3 命令链模式
以松散耦合主题为基础,发送消息、命令和请求,或通过一组处理 程序发送任意内容
命令链模式的应用场景: 1. 登录注册不同角色的业务操作 2. 直播间不同等级会员业务 3. 订单支付状态
interface CommandInterface
{
public function runCommand($name,$argv);
}
class CreateControllerCommand implements CommandInterface
{
public function runCommand($name, $argv)
{
echo "创建控制器".PHP_EOL;
}
}
class CreateModelCommand implements CommandInterface
{
public function runCommand($name, $argv)
{
echo "创建模型".PHP_EOL;
}
}
class Command
{
private $command = [];
public function register(array $command)
{
$this->command = $command;
}
public function run($name,$argv)
{
foreach ($this->command as $key=>$value){
if ($name == $key){
return $value->runCommand($name,$argv);
}
}
}
}
$command = new Command();
$command->register(array(
'controller' => new CreateControllerCommand(),
'model' => new CreateModelCommand()
));
$command->run('model',1);
interface RoleLoginInterface
{
public function handle($name);
}
class bronze implements RoleLoginInterface
{
public function handle($name)
{
echo "欢迎{$name}进入直播间".PHP_EOL;
}
}
class silver implements RoleLoginInterface
{
public function handle($name)
{
echo "欢迎白银会员{$name}进入直播间".PHP_EOL;
}
}
class gold implements RoleLoginInterface
{
public function handle($name)
{
echo "欢迎黄金大神{$name}进入直播间,此时有掌声与音乐".PHP_EOL;
}
}
class Role
{
private $role = [];
public function register(array $role)
{
$this->role = $role;
}
public function LoginEvent($name,$role)
{
foreach ($this->role as $key => $value){
if ($role == $key){
return $value->handle($name);
}
}
}
}
$role = new Role();
$role->register(array(
'bronze' => new bronze(),
'silver' => new silver(),
'gold' => new gold()
));
$role->LoginEvent('harry','bronze');
$role->LoginEvent('xx','gold');
$role->LoginEvent('lori','silver');
2.3.4 迭代器模式
提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该 对象的内部显示
迭代器模式的角色: 1. 迭代器:迭代器定义访问和遍历元素的接口 2. 具体迭代器: 实现迭代器接口,对该聚合遍历时跟踪当前位置 3. 聚合: 聚合实现创建相应迭代器的接口,这个操作是返回具体迭代器的实例
迭代器的优点: 1.多种遍历方式 2.简化聚合类 3.为不同的集合提供统一的接口
迭代器的缺点: 迭代器模式将存储数据和遍历数据的职责分离增加新的集合对象时需要增加 对应的迭代器类,类的个数成对增加,在一定程度上增加系统复杂度
使用场景: 1.访问一个聚合对象的内容而无需暴露它的内部表示 2.支持对聚合对象的多种遍历 3.为遍历不同的聚合结构提供一个统一的接口
class CycleIterator implements Iterator
{
private $array = [];
private $currentIndex = 0;
public function __construct($array)
{
$this->array = $array;
}
public function current()
{
return $this->array[$this->currentIndex];
}
public function setCurrentIndex($currentIndex)
{
$this->currentIndex = $currentIndex;
}
public function setArray($array)
{
$this->array = $array;
}
public function getCurrentIndex()
{
return $this->currentIndex;
}
public function getArray()
{
return $this->array;
}
public function key()
{
return $this->currentIndex;
}
public function next()
{
++$this->currentIndex;
}
public function rewind()
{
$this->currentIndex = 0;
}
public function valid()
{
return isset($this->array[$this->currentIndex]);
}
}
class Cycle implements IteratorAggregate
{
protected $array;
public function __construct($array)
{
$this->array = $array;
}
public function getIterator()
{
return new CycleIterator($this->array);
}
}
$list = [1,2,3,4,5,6,7,8,9];
$cycle= new CycleIterator($list);
foreach ($cycle as $value){
echo $value.PHP_EOL;
}