抽象工厂模式
PHP工厂模式是一种可扩展、可维护和可重复使用的方法,旨在提供通用接口,用于创建对象。工厂模式的主要组成部分包括抽象工厂、具体工厂、抽象产品和具体产品。通过使用工厂模式,可以提高代码复用率和可扩展性,并且可以减少代码耦合度和客户端代码的负担。然而,工厂模式并非适用于所有情况,在使用工厂模式时需要注意局限性和代码复杂性。
示例:
抽象工厂
<?php
namespace App\Design\v1\Msg;
/**
* @Description 生成消息类的工厂
* @Author guo
* @Date 2023/10/8 9:38
**/
interface MsgFactory
{
public function createMsg(): MsgInterFace;
}
抽象对象
<?php
namespace App\Design\v1\Msg;
/**
* @Description 定义消息需实现的接口
* @Author guo
* @Date 2023/10/8 9:37
**/
//定义一个消息发送接口
interface MsgInterFace
{
public function send($data);
}
具体工厂
<?php
namespace App\Design\v1\Msg;
/**
* @Description 实现mqtt推送消息的工厂
* @Author guo
* @Date 2023/10/8 10:55
**/
class MqttFactory implements MsgFactory
{
public function createMsg(): MsgInterFace
{
return new MqttMsg();
}
}
<?php
namespace App\Design\v1\Msg;
/**
* @Description 实现email推送消息的工厂
* @Author guo
* @Date 2023/10/8 10:55
**/
class EmailFactory implements MsgFactory
{
public function createMsg(): MsgInterFace
{
return new EmailMsg();
}
}
具体对象
<?php
namespace App\Design\v1\Msg;
use App\Models\Base\v1\Msg\Msg;
/**
* @Description
* @Author guo
* @Date 2023/10/8 10:58
**/
class MqttMsg implements MsgInterFace
{
public function send($data)
{
//具体实现
$msg = new Msg();
$msg->sendMsg($data);
}
}
<?php
namespace App\Design\v1\Msg;
use App\Models\Base\v1\Msg\Msg;
/**
* @Description
* @Author guo
* @Date 2023/10/8 10:58
**/
class EmailMsg implements MsgInterFace
{
public function send($data)
{
//具体实现
}
}
单例模式
单例设计模式(Singleton Design Pattern)的意思是:一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例模式。
要实现一个单例,需要关注的点有下面几个:
- 构造函数需要是 private 访问权限的,这样才能避免外部通过 new 创建实例;
- 考虑对象创建时的线程安全问题;
- 考虑是否支持延迟加载;
- 考虑 getInstance() 性能是否高(是否加锁)。
单例模式又分为饿汉式单例模式和懒汉式单例模式:
- 饿汉式单例模式:在类加载的时候,instance 静态实例就已经创建并初始化好了,所以,instance 实例的创建过程是线程安全的。不过,这样的实现方式不支持延迟加载实例。采用饿汉式实现方式,将耗时的初始化操作,提前到程序启动的时候完成,这样就能避免在程序运行的时候,再去初始化导致的性能问题。
- 懒汉式单例模式:相对于饿汉式的优势是支持延迟加载。这种实现方式会导致频繁加锁、释放锁,以及并发度低等问题,频繁的调用会产生性能瓶颈。
实例
class ObjectA {
private static $instance = null;
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
//私有化构造函数
private function __construct() {
}
//禁止克隆
private function __clone() {
}
}
$objA1 = ObjectA::getInstance();
$objA2 = ObjectA::getInstance();
var_dump($objA1 === $objA2); //bool(true)
$objA3 = clone $objA1; //此处报错:Fatal error: Uncaught Error: Call to private ObjectC::__clone() from context ''
var_dump($objA1 === $objA3); //程序不会执行到这里
状态模式
什么是状态设计模式
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
什么时候使用状态模式
对象中频繁改变非常依赖于条件语句。 就其自身来说, 条件语句本身没有什么问题(如switch语句或带else子句的语句),不过,
如果选项太多, 以到程序开始出现混乱, 或者增加或改变选项需要花费太多时间, 甚至成为一种负担, 这就出现了问题对于状态设计模式, 每个状态都有自己的具体类, 它们实现一个公共接口. 我们不用查看对象的控制流, 而是从另一个角度来考虑, 即对象的状态.
<?php
class Member
{
private $state;
private $score;
public function SetState($state)
{
$this->state = $state;
}
public function SetScore($score)
{
$this->score = $score;
}
public function GetScore()
{
return $this->score;
}
public function discount()
{
return $this->state->discount($this);
}
}
interface State
{
public function discount($member);
}
class PlatinumMemeberState implements State
{
public function discount($member)
{
if ($member->GetScore() >= 1000) {
return 0.80;
} else {
$member->SetState(new GoldMemberState());
return $member->discount();
}
}
}
class GoldMemberState implements State
{
public function discount($member)
{
if ($member->GetScore() >= 800) {
return 0.85;
} else {
$member->SetState(new SilverMemberState());
return $member->discount();
}
}
}
class SilverMemberState implements State
{
public function discount($member)
{
if ($member->GetScore() >= 500) {
return 0.90;
} else {
$member->SetState(new GeneralMemberState());
return $member->discount();
}
}
}
class GeneralMemberState implements State
{
public function discount($member)
{
return 0.95;
}
}
$m = new Member();
$m->SetState(new PlatinumMemeberState());
$m->SetScore(1200);
echo '当前会员' . $m->GetScore() . '积分,折扣为:' . $m->discount(), PHP_EOL;
$m->SetScore(990);
echo '当前会员' . $m->GetScore() . '积分,折扣为:' . $m->discount(), PHP_EOL;
$m->SetScore(660);
echo '当前会员' . $m->GetScore() . '积分,折扣为:' . $m->discount(), PHP_EOL;
$m->SetScore(10);
echo '当前会员' . $m->GetScore() . '积分,折扣为:' . $m->discount(), PHP_EOL;
状态模式可以把很长的if…else…结构给解构成不同的类,不同的类各自只处理自己职责的部分,但是同样的状态模式没有if…else…结构直观,需要根据实际选择是否使用状态模式
代理模式
为其它对象提供一种代理以控制对这个对象的访问
通俗讲就是需要实现一个方法,但是又不想改变原方法的结构,就可以通过代理将想实现的功能实现再去调用实际执行的操作
<?php
interface SendMessage
{
public function Send();
}
class RealSendMessage implements SendMessage
{
public function Send()
{
echo '短信发送中...', PHP_EOL;
}
}
class ProxySendMessage implements SendMessage
{
private $realSendMessage;
public function __construct($realSendMessage)
{
$this->realSendMessage = $realSendMessage;
}
public function Send()
{
echo '短信开始发送', PHP_EOL;
$this->realSendMessage->Send();
echo '短信结束发送', PHP_EOL;
}
}
$sendMessage = new ProxySendMessage(new RealSendMessage());
$sendMessage->Send();
装饰器模式
组成:
抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
<?php
// 短信模板接口
//定义一个装饰器模式的契约
interface MessageTemplate
{
public function message();
}
// 假设有很多模板实现了上面的短信模板接口
// 下面这个是其中一个优惠券发送的模板实现
class CouponMessageTemplate implements MessageTemplate
{
public function message()
{
return '优惠券信息:我们是全国第一的牛X产品哦,送您十张优惠券!';
}
}
// 我们来准备好装饰上面那个过时的短信模板
/**
装饰者必须实现渲染接口类 RenderInterface 契约,这是该设计模式的关键点。否则,这将不是一个装饰者而只是一个自欺欺人的包装。
创建抽象类 RendererDecorator (渲染器装饰者)实现渲染接口。
*/
abstract class DecoratorMessageTemplate implements MessageTemplate
{
public $template;
public function __construct($template)
{
$this->template = $template;
}
}
// 过滤新广告法中不允许出现的词汇
// 按照DecoratorMessageTemplate契约,实现一个装饰的类
class AdFilterDecoratorMessage extends DecoratorMessageTemplate
{
public function message()
{
return str_replace('全国第一', '全国第二', $this->template->message());
}
}
// 使用我们的大数据部门同事自动生成的新词库来过滤敏感词汇,这块过滤不是强制要过滤的内容,可选择使用
// 按照DecoratorMessageTemplate契约,实现另一个装饰的类
class SensitiveFilterDecoratorMessage extends DecoratorMessageTemplate
{
public $bigDataFilterWords = ['牛X'];
public $bigDataReplaceWords = ['好用'];
public function message()
{
return str_replace($this->bigDataFilterWords, $this->bigDataReplaceWords, $this->template->message());
}
}
// 客户端,发送接口,需要使用模板来进行短信发送
class Message
{
public $msgType = 'old';
public function send(MessageTemplate $mt)
{
// 发送出去咯
if ($this->msgType == 'old') {
echo '面向内网用户发送' . $mt->message() . PHP_EOL;
} else if ($this->msgType == 'new') {
echo '面向全网用户发送' . $mt->message() . PHP_EOL;
}
}
}
$template = new CouponMessageTemplate();
$message = new Message();
// 老系统,用不着过滤,只有内部用户才看得到
$message->send($template);
// 新系统,面向全网发布的,需要过滤一下内容哦
$message->msgType = 'new';
$template1 = new AdFilterDecoratorMessage($template);
$template1 = new SensitiveFilterDecoratorMessage($template);
// 过滤完了,发送吧
$message->send($template1);
/**
* 解析(按AdFilterDecoratorMessage类):
* 1、首先实例化装饰器类 传入需要装饰的基类实例 $template
* 2、调用send方法是将实例化对象 $template1 传进去
* 3、send方法调用传入实例对象的message()方法 进入AdFilterDecoratorMessage类的message()方法 进行具体的操作
*/