Skip to main content

moregeek program

一文搞懂│工厂模式、单例模式、策略模式、适配器模式、观察者模式的原理和使用_autofelix的博客-多极客编程


@[TOC](✨ 目录)



🎈 工厂模式


  • 工厂模式的原理
  • 作用: 就是你只要传你需要的类进去,你就能得到他的实例化对象
  • 其实工厂就是帮你实例化你所需要的类
<?php
/**
* 工厂类
*/
class factory
{
public static function create($className) {
return new $className();
}
}

class A {}
class B {}

$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
*/
interface shape
{
public function area();
public function perimeter();
}

/**
* 矩形
* Class rectangle
*/
class rectangle implements shape
{
private $width;
private $height;

public function __construct($width, $height) {
$this->width = $width;
$this->height = $height;
}

public function area() {
return $this->width * $this->height;
}

public function perimeter() {
return 2 * ($this->width + $this->height);
}
}

/**
* 圆
* Class circle
*/
class circle implements shape
{
private $radius;

public function __construct($radius) {
$this->radius = $radius;
}

public function area() {
return M_PI * pow($this->radius, 2);
}

public function perimeter() {
return 2 * M_PI * $this->radius;
}
}

/**
* 工厂类
* Class factory
*/
class factory
{
public static function create() {
switch (func_num_args()) {
case 1:
return new circle(func_get_arg(0));
break;
case 2:
return new rectangle(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
*/
class A {}

$a = new A();
$b = new A();

// 非单例模式中可以看到其中#1,#2分属不同的内存空间
var_dump($a); // object(A)#1 (0) {}
var_dump($b); // object(A)#2 (0) {}

  • 单例模式的定义
  • 单例模式的入门口诀是:三私一公
  • 私有的构造方法: 防止人为外部使用 new 进行创建这就是上面普通内的实例化了
  • 私有的克隆方法: 防止人为外部使用 clone 方法后进行实例化
  • 私有的静态属性: 用来存储单一的实例化对象
  • 公有的静态方法: 用来实现单一的实例化逻辑
  • 从结果来看﹕两个类的对象内存空间都指向了 #1,实现了单例模式的基础构建
<?php
/**
* Class database
*/
class database
{
/**
* @var $instance
*/
private static $instance;

/**
* 私有的构造方法,禁止外部实例化
* database constructor.
*/
private function __construct() {}

/**
* 私有的克隆方法,禁止外部克隆
*/
private function __clone() {}

/**
* 获取单例
* @return database
*/
public static function getInstance()
{
if(!self::$instance instanceof self) {
self::$instance = new self();
}

return self::$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
*/
class mysql
{
/**
* @var \PDO
*/
private $pdo;

/**
* @var $instance
*/
private static $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.
*/
private function __construct() {}

/**
* 数据库链接
*/
public function connect()
{
try {
$dsn = "mysql:host={$this->_config['host']};port={$this->_config['post']};dbname={$this->_config['dbname']};charset={$this->_config['charset']}";
$this->pdo = new PDO($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
*/
public function getAll($sql)
{
$this->sql = $sql;
$pdostatement = $this->pdo->query($sql);
return $pdostatement->fetchAll(PDO::FETCH_ASSOC);
}

/**
* @return mysql
*/
public static function getInstance()
{
if(!self::$instance instanceof self) {
self::$instance = new self();
}
return self::$instance;
}

private function __clone() {}
}

$mysql = mysql::getInstance();
$mysql->connect();

$sql = 'select * from autofelix_users where 1';
$result = $mysql->getAll($sql);
echo json_encode($result);

🎈 策略模式


  • 策略模式的原理
  • 作用: 比如你去淘宝上买东西,如果你是男生,它的首页会给你推荐男生喜欢的物品,如果你是女生呢,它会给你推荐女生常用的物品,策略模式其实就是给对象进行分类
  • 由上面可知,编程中的策略模式,就是会知道你是什么人,然后给你推荐你喜欢的东西,让营销最大化
  • 这里必然涉及到,程序在运行的时候,给你这个人进行分门别类,然后执行了不同的方法导致的
  • 这里我们定义两个类,拥有相同的方法,执行的内容却不同
  • 策略模式需要做的就是当用户进来时候,同一个入口让他根据这个人的行为去执行其中某一个类中的方法
<?php
/**
* Class A
*/
class A {
public function name()
{
echo "我是A类";
}
}

/**
* Class B
*/
class B {
public function name()
{
echo "我是B类";
}
}

/**
* Class strategy
*/
class strategy
{
/**
* @var $obj
*/
private $obj;

/**
* @return mixed
*/
public function getName()
{
return $this->obj->name();
}

/**
* @param $class
*/
public function setClass($class)
{
$this->obj = $class;
}
}

$strategy = new strategy();
// 分门别类
// $strategy->setClass(new A());
$strategy->setClass(new B());
// 同一个入口
$strategy->getName(); // 我是B类

  • 策略模式的应用
  • 情景: 一个用户去某酒店网站定住宿为例,页面上根据你的历史消费记录,会为你显示高等住宿和丰富的晚餐,或者仅仅显示大众住宿和廉价的自助餐
  • 我们先定义接口去实现住房和晚餐的方法
  • 然后定义两个群里的类去实现这个接口,分别是尊贵的人群和普通的人群
  • 当有个autofelix用户去订房间,给他注入大众用户的类
<?php
/**
* 定义接口
* Interface userStrategy
*/
interface userStrategy
{
public function hotel();
public function dinner();
}

/**
* 尊贵的客人享有的待遇
* Class rich
*/
class rich implements userStrategy
{
public function hotel()
{
return "你是高贵的客人,为你推荐了高级住宿";
}

public function dinner()
{
return "你是高贵的客人,为你推荐了烛光晚餐";
}
}

/**
* 普通的客人享有的待遇
* Class poor
*/
class poor implements userStrategy
{
public function hotel()
{
return "你是普通的客人,为你推荐了大众住宿";
}

public function dinner()
{
return "你是普通的客人,为你推荐了自助餐";
}
}

/**
* Class user
*/
class user
{
private $_userClass;

public function getHotel() {
return $this->_userClass->hotel();
}

public function getDinner() {
return $this->_userClass->dinner();
}

public function setUserClass(userStrategy $userStrategy) {
$this->_userClass = $userStrategy;
}
}

/**
* 这时候有个autofelix用户过来网站预定房间
* Class autofelix
*/
class autofelix extends user {}

$people = new autofelix();

//设置群体
$people->setUserClass(new poor());

//获取该群体的住宿和晚餐
$hotel = $people->getHotel();
$dinner = $people->getDinner();

echo json_encode([
'hotel' => $hotel,
'dinner' => $dinner
]);

// 结果如下
{
hotel: "你是普通的客人,为你推荐了大众住宿",
dinner: "你是普通的客人,为你推荐了自助餐"
}

🎈 适配器模式


  • 适配器模式的原理
  • 作用: 将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能一起工作的那些类可以一起工作
  • 比如:在某个场景中,老项目写了很多接口公你调用,但突然有一天,上司说要换个接口方法名调用,需要你用另一个方法名去实现相同的功能
  • 你是直接改后端代码的方法名称?这肯定行不通,因为项目不止你这一个地方调用这个接口,一旦修改,其他地方就崩了,还是去重新复制那段逻辑代码,改个名字,这样不是不行,只是写了重复代码,显得臃肿了
<?php

class A
{
private $str;

public function __construct($str)
{
$this->str = $str;
}

public function getStr()
{
return $this->str;
}

// 错误示范,直接复制 getStr 中的代码改个方法名,臃肿
public function getString()
{
return $this->str;
}
}

//适配器模式前
$a = new A('i am autofelix');
$result = $a->getStr();
var_dump($result);

  • 适配器模式的应用
  • 而正确的常见,应该是使用适配器模式处理这类问题
  • 通过定义统一接口,然后通过实现接口去实现
<?php
// 项目原本代码
class A
{
private $str;

public function __construct($str)
{
$this->str = $str;
}

public function getStr()
{
return $this->str;
}
}

// 定义统一接口
interface AInterface {
function getString();
}

class B implements AInterface
{
/**
* @var A
*/
private $_A;

public function __construct($class)
{
$this->_A = $class;
}

public function getString()
{
return $this->_A->getStr();
}
}

// 适配器模式前
$a = new A('i am autofelix');
$result = $a->getStr();
var_dump($result);

// 适配器模式后
$b = new B($a);
$result = $b->getString();
var_dump($result);

🎈 观察者模式


  • 观察者模式的原理
  • 作用: 用来监控用户的某些操作,然后根据用户这些操作来处理一些后续的事情
  • 举个例子:一个用户去网上购买电影票,付款成功后,系统需要发短信给用户,顺便记录用户购票的日志等其他多个逻辑操作
// 系统自带的观察者接口
// 默认需要实现 onListen 和 getObserverName 这两个方法
// 如果是自定义观察者接口名,一定要实现onListen同功能的方法
// onListen 注册监听行为
interface InterfaceObserver
{
public function onListen($sender, $args);
public function getObserverName();
}

// 定义可被观察者的接口
// 其实就是用来监听事件的发生
// addObserver 方法我们是用来依赖注入一些用户购票之后系统的行为操作
// removeObserver 方法,是用来移除某个后续操作的,我们暂时不去实现
interface InterfaceObservable
{
public function addObserver($observer);
public function removeObserver($observer_name);
}

  • 观察者模式的应用
  • 这里以用户购票后需要给用户发送信息和记录购票日志
<?php
/**
* Interface InterfaceObserver
* 观察者接口
*/
interface InterfaceObserver
{
public function onListen($sender, $args);
public function getObserverName();
}

/**
* Interface InterfaceObservable
* 被观察对象接口
*/
interface InterfaceObservable
{
public function addObserver($observer);
public function removeObserver($observer_name);
}

class Ticket implements InterfaceObservable
{
/**
* @var array
*/
private $_observers = [];

/**
* @param $observer
*/
public function addObserver($observer)
{
if ($observer instanceof InterfaceObserver) {
$this->_observers[] = $observer;
}
}

/**
* @param $observer_name
*/
public function removeObserver($observer_name) {}

/**
* 用户购票行为
*/
public function buy()
{
//用户购票逻辑,这里不详细说明,仅仅以参数代之
$result = [
'code' => 200,
'msg' => '用户购票成功',
'sign' => 'ea5070bec29826cc0f8e0b7b6861fd75'
];

//购票成功,开始后期处理
if($result['code'] == 200) {
foreach ($this->_observers as $observer) {
$observer->onListen($this, $result['sign']);
}
}
}
}

/**
* 记录用户购票日志
* Class TicketRecord
*/
class ticketRecord implements InterfaceObserver
{
public function onListen($sender, $args)
{
echo "记录用户购票成功,编号为:{$args}<br/>";
}

public function getObserverName() {}
}

/**
* 给用户发送观影短信
* Class sendMsg
*/
class sendMsg implements InterfaceObserver
{
public function onListen($sender, $args)
{
echo "您的电影票购买成功,请凭编号:{$args}观影<br/>";
}

public function getObserverName() {}
}

$ticket = new Ticket();
$ticket->addObserver(new ticketRecord());
$ticket->addObserver(new sendMsg());
$ticket->buy();

解读go分布式链路追踪实现原理_华为云开发者社区的博客-多极客编程

摘要:本文将详细介绍分布式链路的核心概念、架构原理和相关开源标准协议,并分享我们在实现无侵入 Go 采集 Sdk 方面的一些实践。本文分享自华为云社区《​​一文详解|Go 分布式链路追踪实现原理​​》,作者:开源小E。在分布式、微服务架构下,应用一个请求往往贯穿多个分布式服务,这给应用的故障排查、性能优化带来新的挑战。分布式链路追踪作为解决分布式应用可观测问题的重要技术,愈发成为分布式应用不可缺少

springboot接口 - 如何优雅的对参数进行校验?_wx607590ac4ce05的博客-多极客编程

在以SpringBoot开发Restful接口时, 对于接口的查询参数后台也是要进行校验的,同时还需要给出校验的返回信息放到上文我们统一封装的结构中。那么如何优雅的进行参数的统一校验呢? @pdai什么是不优雅的参数校验后端对前端传过来的参数也是需要进行校验的,如果在controller中直接校验需要用大量的if else做判断以添加用户的接口为例,需要对前端传过来的参数进行校验, 如下的校验就是

#yyds干货盘点# leetcode算法题:n皇后 ii_灰太狼_cxh的博客-多极客编程

题目:n 皇后问题 研究的是如何将 n 个皇后放置在 n × n 的棋盘上,并且使皇后彼此之间不能相互攻击。给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量。输入:n = 4输出:2解释:如上图所示,4 皇后问题存在两个不同的解法。示例 2:输入:n = 1输出:1代码实现:class Solution { public int totalNQueens(int n) {

微信红包业务,为什么采用轮询算法?_wx6135b7119b442的博客-多极客编程

目录前言基本的负载算法平滑加权轮询算法一致性哈希算法最小活跃数算法最优响应算法总结前言负载均衡这个概念,几乎在所有支持高可用的技术栈中都存在,例如微服务、分库分表、各大中间件(MQ、Redis、MyCat、Nginx、ES)等,也包括云计算、云调度、大数据中也是炙手可热的词汇。负载均衡策略主要分为静态与动态两大类:**静态调度算法:**指配置后只会依据配置好的策略进行请求分发的算法。**动态调度算

java 基础教程 - 使用 switch ... case 制作简易计算器_wx6123051953ddd的博客-多极客编程

Java 是一款在 1995 年面世的高级编程语言。由 Sun Microsystems 开发而成的这款编程语言可在 Windows、MacOS 及 UNIX 等多种不同的平台上运行,而 Java 也可用于编写电脑、服务器、手机、浏览器、蓝光机等不同的软硬件。Java 诞生至今已有相当大的改变,其后来由甲骨文(Oracle)收购,同时也在近 30 年间建立了庞大的开发者社区以及开源库。Java 的

20220712 go语言基础知识_歆瑶的小房子的博客-多极客编程

基础 1. 内置函数2. 流程控制2.1. if与switch2.1.1. if2.1.2. switch2.2. for3. 指针3.1. 指针地址和指针类型3.2. 指针取值3.3. 空指针4. 数组Array4.1. 数组定义4.2. 数组定义4.3. 与数组相关的函数5. 切分Slice5.1. 切分Slice定义5.2. 切分Slice初始化5.3. cap与len5.4. 操作方法5.

初创企业的物联网产品开发指南_wot技术大会的博客-多极客编程

调查表明,75%的物联网项目最终失败。为了避免这种情况,企业应该事先仔细规划物联网项目,并熟悉物联网产品开发的各个阶段。微软公司在2021年发布的《IoT Signals》调查报告中指出,90%的企业已经采用物联网解决方案来降低运营成本、释放额外的收入流,并获得竞争优势。 然而,35%的物联网项目在概念验证(POC)阶段停滞不前,而75%的物联网的计划从未实现,没有开发出可上市的产品。 致力开发物

图扑软件数字孪生智慧风电 | 云上协同,智能研判_图扑-数字孪生的博客-多极客编程

“双碳”目标提出后,为了提升能源利用效率、降低碳排放,很多行业都开展了电能替代。2022 年一季度,我国可再生能源新增装机 2541 万千瓦,占全国新增发电装机的 80%。其中,水电新增 343 万千瓦、风电新增 790 万千瓦、光伏发电新增 1321 万千瓦、生物质发电新增 87 万千瓦。截至 2022 年 3 月底,我国可再生能源发电装机达 10.88 亿千瓦。在新能源风电领域,风力发电机通过

【服务器数据恢复】华为oceanstor某型号存储中nas卷数据丢失的数据恢复案例_sun的博客-多极客编程

服务器数据恢复环境: 华为OceanStor某型号存储,支持SAN和NAS存储协议。 服务器故障: 存储上一个NAS卷中的数据丢失,卷大小为2T,管理员发现后,关闭系统应用,停止上传数据。 经过检查发现丢失数据的类型为office文档、PDF文件、图片文件(JPG、JPEG、PNG等)、视频文件(MP4、AVI等)、音频文件(MP3等)。 服务器管理员联系我们数据恢复中心进行数据恢复。 服务器数据

spring认证证书有用吗?_spring认证的博客-多极客编程

Spring认证(全称:Spring Professional认证)是Spring官方推出的认证体系,旨在测试和验证学生对 Spring 和 Spring Boot核心方面的理解和熟悉程度,例如:配置、组件扫描、AOP、数据访问和事务、REST、安全、自动配置、执行器、 Spring boot测试等。目前Spring认证的版本:Spring v5.0(VMware EDU-1202),认证终生有效

【数据分析师---数据分析基础】第三章:pandas功能介绍及应用_wx62cb940602a10的博客-多极客编程

第三章:Pandas功能介绍及应用​​1 Csv和Excel文件读取与写入​​​​1.1 Csv文件读取与写入​​​​1.1.1 Csv数据读取​​​​1.1.2 跳过指定行读取数据​​​​1.1.3 字段名称操作​​​​1.1.4 读取指定数量的数据​​​​1.1.5 数据存入Csv​​​​1.2 Excel数据读取与写入​​​​1.2.1 Excel数据默认读取​​​​1.2.2 指定shee

!-2022.07.12-文件和文件夹管理办法-v2.0_ds920的博客-多极客编程

    1.文件定义   本文的文件是指由手机、笔记本电脑、平板电脑、台式电脑、扫描仪、高拍仪、照相机、录像机生成的或者由手机、笔记本电脑、平板电脑、台式电脑、群晖NAS下载的电子文件。例如:有声读物、音乐、歌曲、docx文档、xlsx表格、jpg图片、视频、电影、连续剧、脚本程序、应用软件、单机游戏、网络游戏等各种类型电子文件资源。   2.文件保存   所有文件和文件夹的最新编辑修改版