工厂模式、单例模式、策略模式、适配器模式、观察者模式的原理和使用详解

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS AI 助手,专业版
简介: 学好设计模式,让你的逻辑活起来

🎈 工厂模式

  • 工厂模式的原理
  • 作用: 就是你只要传你需要的类进去,你就能得到他的实例化对象
  • 其实工厂就是帮你实例化你所需要的类
<?php/*** 工厂类*/classfactory{
publicstaticfunctioncreate($className) {
returnnew$className();
    }
}
classA {}
classB {}
$a=factory::create('A');
$b=factory::create('B');
var_dump($a); // object(A)#1 (0) {}var_dump($b); // object(B)#2 (0) {}
  • 工厂模式的应用
  • 实例化多个类来处理不同业务时候使用,这里以求矩形和圆形的周长和面积为案例
<?php/*** Interface shape*/interfaceshape{
publicfunctionarea();
publicfunctionperimeter();
}
/*** 矩形* Class rectangle*/classrectangleimplementsshape{
private$width;
private$height;
publicfunction__construct($width, $height) {
$this->width=$width;
$this->height=$height;
    }
publicfunctionarea() {
return$this->width*$this->height;
    }
publicfunctionperimeter() {
return2* ($this->width+$this->height);
    }
}
/*** 圆* Class circle*/classcircleimplementsshape{
private$radius;
publicfunction__construct($radius) {
$this->radius=$radius;
    }
publicfunctionarea() {
returnM_PI*pow($this->radius, 2);
    }
publicfunctionperimeter() {
return2*M_PI*$this->radius;
    }
}
/*** 工厂类* Class factory*/classfactory{
publicstaticfunctioncreate() {
switch (func_num_args()) {
case1:
returnnewcircle(func_get_arg(0));
break;
case2:
returnnewrectangle(func_get_arg(0), func_get_arg(1));
break;
        }
    }
}
$a=factory::create(4, 5);
$b=factory::create(2);
echo'矩形的周长为:' . $a->perimeter();
echo'矩形的面积为:' . $a->area();
echo'圆的周长为:' . $a->perimeter();
echo'圆的面积为:' . $a->area();


🎈 单例模式

  • 单例模式的原理
  • 作用: 当你实例化多次类的时候,让其只存在在唯一的内存空间中,减少资源的消耗
  • 普通类的实例化,一个 new 将会创建一个实例化内存空间,因为空间不同,这将会导致系统内存开销增大
  • 但是同一个类,功能都一样,没必要放在不同的内存空间中
<?php/*** Class A*/classA {}
$a=newA();
$b=newA();
// 非单例模式中可以看到其中#1,#2分属不同的内存空间var_dump($a); // object(A)#1 (0) {}var_dump($b); // object(A)#2 (0) {}
  • 单例模式的定义
  • 单例模式的入门口诀是:三私一公
  • 私有的构造方法: 防止人为外部使用 new 进行创建这就是上面普通内的实例化了
  • 私有的克隆方法: 防止人为外部使用 clone 方法后进行实例化
  • 私有的静态属性: 用来存储单一的实例化对象
  • 公有的静态方法: 用来实现单一的实例化逻辑
  • 从结果来看:两个类的对象内存空间都指向了 #1,实现了单例模式的基础构建
<?php/*** Class database*/classdatabase{
/*** @var $instance*/privatestatic$instance;
/*** 私有的构造方法,禁止外部实例化* database constructor.*/privatefunction__construct() {}
/*** 私有的克隆方法,禁止外部克隆*/privatefunction__clone() {}
/*** 获取单例* @return database*/publicstaticfunctiongetInstance()
    {
if(!self::$instanceinstanceofself) {
self::$instance=newself();
        }
returnself::$instance;
    }
}
$a=database::getInstance();
$b=database::getInstance();
var_dump($a); // object(database)#1 (0) {}var_dump($b); // object(database)#1 (0) {}
  • 单例模式的应用
  • 其实在项目中单例模式的应用很多,无非就是有些东西只需要实例化一个对象就行了,不需要多次进行实例化
  • 这其中的应用场景常见的就包括PDO连接数据库,Redis的连接等等
<?php/*** Class mysql*/classmysql{
/*** @var \PDO*/private$pdo;
/*** @var $instance*/privatestatic$instance;
/*** @var array*/private$_config= [
'host'=>'127.0.0.1',
'post'=>3306,
'user'=>'root',
'password'=>'',
'charset'=>'utf8',
'dbname'=>'autofelix',
'except'=>'PDO::ERRMODE_EXCEPTION'    ];
/*** mysql constructor.*/privatefunction__construct() {}
/*** 数据库链接*/publicfunctionconnect()
    {
try {
$dsn="mysql:host={$this->_config['host']};port={$this->_config['post']};dbname={$this->_config['dbname']};charset={$this->_config['charset']}";
$this->pdo=newPDO($dsn, $this->_config['user'], $this->_config['password']);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, $this->_config['except']);
        } catch (PDOException$e) {
exit('数据库连接失败:' . $e->getMessage());
        }
    }
/*** @param $sql* @return array*/publicfunctiongetAll($sql)
    {
$this->sql=$sql;
$pdostatement=$this->pdo->query($sql);
return$pdostatement->fetchAll(PDO::FETCH_ASSOC);
    }
/*** @return mysql*/publicstaticfunctiongetInstance()
    {
if(!self::$instanceinstanceofself) {
self::$instance=newself();
        }
returnself::$instance;
    }
privatefunction__clone() {}
}
$mysql=mysql::getInstance();
$mysql->connect();
$sql='select * from autofelix_users where 1';
$result=$mysql->getAll($sql);
echojson_encode($result);


🎈 策略模式

  • 策略模式的原理
  • 作用: 比如你去淘宝上买东西,如果你是男生,它的首页会给你推荐男生喜欢的物品,如果你是女生呢,它会给你推荐女生常用的物品,策略模式其实就是给对象进行分类
  • 由上面可知,编程中的策略模式,就是会知道你是什么人,然后给你推荐你喜欢的东西,让营销最大化
  • 这里必然涉及到,程序在运行的时候,给你这个人进行分门别类,然后执行了不同的方法导致的
  • 这里我们定义两个类,拥有相同的方法,执行的内容却不同
  • 策略模式需要做的就是当用户进来时候,同一个入口让他根据这个人的行为去执行其中某一个类中的方法
<?php/*** Class A*/classA {
publicfunctionname()
    {
echo"我是A类";
    }
}
/*** Class B*/classB {
publicfunctionname()
    {
echo"我是B类";
    }
}
/*** Class strategy*/classstrategy{
/*** @var $obj*/private$obj;
/*** @return mixed*/publicfunctiongetName()
    {
return$this->obj->name();
    }
/*** @param $class*/publicfunctionsetClass($class)
    {
$this->obj=$class;
    }
}
$strategy=newstrategy();
// 分门别类// $strategy->setClass(new A());$strategy->setClass(newB());
// 同一个入口$strategy->getName(); // 我是B类
  • 策略模式的应用
  • 情景:  一个用户去某酒店网站定住宿为例,页面上根据你的历史消费记录,会为你显示高等住宿和丰富的晚餐,或者仅仅显示大众住宿和廉价的自助餐
  • 我们先定义接口去实现住房和晚餐的方法
  • 然后定义两个群里的类去实现这个接口,分别是尊贵的人群和普通的人群
  • 当有个autofelix用户去订房间,给他注入大众用户的类
<?php/*** 定义接口* Interface userStrategy*/interfaceuserStrategy{
publicfunctionhotel();
publicfunctiondinner();
}
/*** 尊贵的客人享有的待遇* Class rich*/classrichimplementsuserStrategy{
publicfunctionhotel()
    {
return"你是高贵的客人,为你推荐了高级住宿";
    }
publicfunctiondinner()
    {
return"你是高贵的客人,为你推荐了烛光晚餐";
    }
}
/*** 普通的客人享有的待遇* Class poor*/classpoorimplementsuserStrategy{
publicfunctionhotel()
    {
return"你是普通的客人,为你推荐了大众住宿";
    }
publicfunctiondinner()
    {
return"你是普通的客人,为你推荐了自助餐";
    }
}
/*** Class user*/classuser{
private$_userClass;
publicfunctiongetHotel() {
return$this->_userClass->hotel();
    }
publicfunctiongetDinner() {
return$this->_userClass->dinner();
    }
publicfunctionsetUserClass(userStrategy$userStrategy) {
$this->_userClass=$userStrategy;
    }
}
/*** 这时候有个autofelix用户过来网站预定房间* Class autofelix*/classautofelixextendsuser {}
$people=newautofelix();
//设置群体$people->setUserClass(newpoor());
//获取该群体的住宿和晚餐$hotel=$people->getHotel();
$dinner=$people->getDinner();
echojson_encode([
'hotel'=>$hotel,
'dinner'=>$dinner]);
// 结果如下{
hotel: "你是普通的客人,为你推荐了大众住宿",
dinner: "你是普通的客人,为你推荐了自助餐"}


🎈 适配器模式

  • 适配器模式的原理
  • 作用: 将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能一起工作的那些类可以一起工作
  • 比如:在某个场景中,老项目写了很多接口公你调用,但突然有一天,上司说要换个接口方法名调用,需要你用另一个方法名去实现相同的功能
  • 你是直接改后端代码的方法名称?这肯定行不通,因为项目不止你这一个地方调用这个接口,一旦修改,其他地方就崩了,还是去重新复制那段逻辑代码,改个名字,这样不是不行,只是写了重复代码,显得臃肿了
<?phpclassA{
private$str;
publicfunction__construct($str)
    {
$this->str=$str;
    }
publicfunctiongetStr()
    {
return$this->str;
    }
// 错误示范,直接复制 getStr 中的代码改个方法名,臃肿publicfunctiongetString()
    {
return$this->str;
    }
}
//适配器模式前$a=newA('i am autofelix');
$result=$a->getStr();
var_dump($result);
  • 适配器模式的应用
  • 而正确的常见,应该是使用适配器模式处理这类问题
  • 通过定义统一接口,然后通过实现接口去实现
<?php// 项目原本代码classA{
private$str;
publicfunction__construct($str)
    {
$this->str=$str;
    }
publicfunctiongetStr()
    {
return$this->str;
    }
}
// 定义统一接口interfaceAInterface {
functiongetString();
}
classBimplementsAInterface{
/*** @var A*/private$_A;
publicfunction__construct($class)
    {
$this->_A=$class;
    }
publicfunctiongetString()
    {
return$this->_A->getStr();
    }
}
// 适配器模式前$a=newA('i am autofelix');
$result=$a->getStr();
var_dump($result);
// 适配器模式后$b=newB($a);
$result=$b->getString();
var_dump($result);


🎈 观察者模式

  • 观察者模式的原理
  • 作用: 用来监控用户的某些操作,然后根据用户这些操作来处理一些后续的事情
  • 举个例子:一个用户去网上购买电影票,付款成功后,系统需要发短信给用户,顺便记录用户购票的日志等其他多个逻辑操作
<?php// 系统自带的观察者接口// 默认需要实现 onListen 和 getObserverName 这两个方法// 如果是自定义观察者接口名,一定要实现onListen同功能的方法// onListen 注册监听行为interfaceInterfaceObserver{
publicfunctiononListen($sender, $args);
publicfunctiongetObserverName();
}
// 定义可被观察者的接口// 其实就是用来监听事件的发生// addObserver 方法我们是用来依赖注入一些用户购票之后系统的行为操作// removeObserver 方法,是用来移除某个后续操作的,我们暂时不去实现interfaceInterfaceObservable{
publicfunctionaddObserver($observer);
publicfunctionremoveObserver($observer_name);
}
  • 观察者模式的应用
  • 这里以用户购票后需要给用户发送信息和记录购票日志
<?php/*** Interface InterfaceObserver* 观察者接口*/interfaceInterfaceObserver{
publicfunctiononListen($sender, $args);
publicfunctiongetObserverName();
}
/*** Interface InterfaceObservable* 被观察对象接口*/interfaceInterfaceObservable{
publicfunctionaddObserver($observer);
publicfunctionremoveObserver($observer_name);
}
classTicketimplementsInterfaceObservable{
/*** @var array*/private$_observers= [];
/*** @param $observer*/publicfunctionaddObserver($observer)
    {
if ($observerinstanceofInterfaceObserver) {
$this->_observers[] =$observer;
        }
    }
/*** @param $observer_name*/publicfunctionremoveObserver($observer_name) {}
/*** 用户购票行为*/publicfunctionbuy()
    {
//用户购票逻辑,这里不详细说明,仅仅以参数代之$result= [
'code'=>200,
'msg'=>'用户购票成功',
'sign'=>'ea5070bec29826cc0f8e0b7b6861fd75'        ];
//购票成功,开始后期处理if($result['code'] ==200) {
foreach ($this->_observersas$observer) {
$observer->onListen($this, $result['sign']);
            }
        }
    }
}
/*** 记录用户购票日志* Class TicketRecord*/classticketRecordimplementsInterfaceObserver{
publicfunctiononListen($sender, $args)
    {
echo"记录用户购票成功,编号为:{$args}<br/>";
    }
publicfunctiongetObserverName() {}
}
/*** 给用户发送观影短信* Class sendMsg*/classsendMsgimplementsInterfaceObserver{
publicfunctiononListen($sender, $args)
    {
echo"您的电影票购买成功,请凭编号:{$args}观影<br/>";
    }
publicfunctiongetObserverName() {}
}
$ticket=newTicket();
$ticket->addObserver(newticketRecord());
$ticket->addObserver(newsendMsg());
$ticket->buy();
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
开发框架 NoSQL .NET
.NET Core MongoDB的简单使用
.NET Core MongoDB的简单使用
406 0
|
2月前
|
UED 开发者
Axure Web端元件库:设计师的高效利器
Axure Web端元件库融合高保真、丰富交互与海量案例,支持Axure 8-10版本,涵盖500+高质量组件,助力设计师高效打造接近真实产品的原型,提升协作效率与创意表达。
135 0
|
7月前
|
安全 Java 数据库
第16课:Spring Boot中集成 Shiro
第16课:Spring Boot中集成 Shiro
940 0
|
7月前
|
存储 缓存 算法
《WebGL打造高性能3D粒子特效系统:从0到1的技术探秘》
本文围绕WebGL构建高性能3D粒子特效系统展开技术探秘。首先介绍WebGL渲染管线的核心机制,阐述从顶点数据处理到光栅化呈现的完整流程;接着讲解数据结构设计的重要性,包括结构数组(SoA)和粒子池的应用;然后说明物理模拟如何赋予粒子自然运动效果,涉及重力、风力、碰撞等模拟方式;还探讨了光影效果与材质渲染的实现,以及性能优化的关键策略,如减少绘制调用、视锥体剔除、资源缓存等。通过这些技术细节与优化技巧,为游戏、可视化项目等打造出流畅且富视觉冲击力的3D粒子特效提供了全面参考。
280 0
|
前端开发 应用服务中间件 数据库
Docker-docker-compose学习笔记(yaml,实战)
Docker-docker-compose学习笔记(yaml,实战)
1107 0
|
开发工具 git
解决pre-commit hook failed (add --no-verify to bypass)的问题
该文介绍了两种免去Git预提交钩子(pre-commit)的方法。一是直接进入项目.git/hooks目录,使用`rm -rf ./git/hooks/pre-commit`命令删除pre-commit文件。二是提交时添加`--no-verify`参数,如`git commit --no-verify -m&quot;XXX&quot;`,以跳过预提交检查。
996 0
|
JavaScript Java 关系型数据库
美食分享|基于Springboot和vue的地方美食分享网站系统设计与实现(源码+数据库+文档)
美食分享|基于Springboot和vue的地方美食分享网站系统设计与实现(源码+数据库+文档)
747 0
|
JavaScript Java 测试技术
基于SpringBoot+Vue的美食分享系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的美食分享系统的详细设计和实现(源码+lw+部署文档+讲解等)
306 0
|
设计模式 算法 Java
Java中的设计模式:实战案例分享
Java中的设计模式:实战案例分享