// 多态, 在JAVA中是这样用的, 其实在PHP当中可以自然消除, 因为参数是动态的, 你传什么过来都可以, 不限制类型, 直接调用类的方法
abstract class Tiger {
public abstract function climb();
}
class XTiger extends Tiger {
public function climb() {
echo '摔下来';
}
}
class MTiger extends Tiger {
public function climb() {
echo '爬到树顶';
}
}
class Client {
public static function call(Tiger $animal) {
$animal->climb();
}
}
Client::call(new XTiger());
Client::call(new MTiger());// 面向对象里面有一个面向接口开发, 就是一个共同的规格, 你生产插座, 我生产插头
// 共同接口
interface db {
function conn();
}
// 服务端开发(不知道将会被谁调用)
class dbmysql implements db{
public function conn() {
echo '连上了MySQL';
}
}
class dbsqlite implements db{
public function conn() {
echo '连上了sqlite';
}
}
// 客户端, 看不到dbmysql, dbsqlite的内部细节的, 只知道上两个类实现了db接口.
$db = new dbmysql();
$db->conn(); // 因为知道这个类实现了db接口, 所以知道有这个conn类
$sqlite = new dbsqlite();
$sqlite->conn();
// 我连我有哪些类我都不希望告诉客户端, 那么怎么进一步进行封装
// 发生连接的双方知道的越少越好, 你还知道我有两个类// 简单工厂
// 面向对象里面有一个面向接口开发, 就是一个共同的规格, 你生产插座, 我生产插头
// 共同接口
interface db {
function conn();
}
// 服务端开发(不知道将会被谁调用)
class dbmysql implements db{
public function conn() {
echo '连上了MySQL';
}
}
class dbsqlite implements db{
public function conn() {
echo '连上了sqlite';
}
}
// 简单工厂
class Factory {
public static function createDB($type) {
if($type == 'mysql') {
return new dbmysql();
} elseif ($type=='sqlite') {
return new dbsqlite();
} else {
throw new Exception("Error db type", 1);
}
}
}
// 客户端现在不知道对方到底有哪些类名了
// 只知道对方开放了一个Factory::createDB方法
// 方法允许传递数据库名称
$mysql = Factory::createDB('mysql');
$mysql->conn();
$sqlite = Factory::createDB('sqlite');
$sqlite->conn();
// 原本你知道服务器端的两个类名, 觉得你知道的太多, 再封装起来, 只给一个通道, 更好的适应变化
// 如果以后新增oracle类型, 怎么办?
// 我们PHP随手改了就行, 像JAVA打包一次很麻烦, 又要修改服务端内容
// 服务端要修改Factory的内容(在java, c++中, 改后还得再编译)
// 这个时候就想如何来改进呢
// 在OOD(面向对象设计)的法则中, 有重要的开闭原则--对于修改是封闭的, 对于扩展是开放的.
// 你可以新增一个源代码, 不要修改旧的代码
//现在用第二种办法, 叫工厂方法// 共同接口
interface db {
function conn();
}
interface Factory {
function createDB();
}
// 服务端开发(不知道将会被谁调用)
class dbmysql implements db{
public function conn() {
echo '连上了MySQL';
}
}
class dbsqlite implements db{
public function conn() {
echo '连上了sqlite';
}
}
class mysqliFactory implements Factory{
public function createDB() {
return new dbmysql();
}
}
class sqliteFactory implements Factory {
public function createDB() {
return new dbsqlite();
}
}
// 服务器端添加oracle类
// 前面的代码不用改
// 我就新增一个数据库驱动类和一个工厂, 这样就避免了对源代码的修改
class dboracle implements db {
public function conn() {
echo '连接上了oracle';
}
}
class oracleFactory implements Factory {
public function createDB() {
return new dboracle();
}
}
// 客户端开始, 对方给了两个api, 一个db的api, 一个是创造数据库的api
$fact = new mysqliFactory();
$db = $fact->createDB();
$db->conn();
$fact = new sqliteFactory();
$db = $fact->createDB();
$db->conn();// 单例
// 一般来说一个中小型网站一个db去连接数据库就行了
// 想想, 能不能只有一个db类, 一个upload类, 一个cookie类
// 类肯定只有一个, 如何保证类的实例也只有一个
// 2个对象是同一个的时候才全等
// 单例模式
class single {
protected static $ins = null;
// 控制权限, 封锁new操作, 把大门关上了, 需要留一个小窗户
// 方法前加final, 则方法不能被覆盖, 类前加final, 则类不能被继承
final protected function __construct() {}
// 防clone
final protected function __clone(){}
//留一个接口来new对象
public static function getIns() {
if(self::$ins == null) {
self::$ins = new self();
}
return self::$ins;
}
}
$s1 = single::getIns();
$s2 = single::getIns();
if ($s1 === $s2) {
echo '是一个对象';
} else {
echo '不是一个对象';
}<!DOCTYPE HTML>
<html>
<head>
<title>colour_blue</title>
<meta name="description" c />
<meta name="keywords" c />
<meta http-equiv="content-type" c />
<style>
div{
margin:10px;
width:500px;
height:200px;
border: 1px solid green;
}
#content {
}
#ad {
}
</style>
<script>
function t() {
var sel = document.getElementsByTagName('select')[0];
// alert(sel.value);
if(sel.value == 'male') {
document.getElementById('content').style.backgroundColor = 'gray';
document.getElementById('ad').innerHTML = '汽车';
} else if(sel.value=='female') {
document.getElementById('content').style.backgroundColor = 'pink';
document.getElementById('ad').innerHTML = '减肥';
}
}
/**
*
* 观察上述代码, 如果新增了一个study区, 在切换时, 学习内容也要随之切换, 那么, 就需要改动T函数! 对于修改又开放了.
* 思考---如果需要新监听footer区, 如何能不改原来的代码, 而只增加
*/
</script>
</head>
<body>
<h1>面向过程, 不用任务来切换</h1>
<select name="" name="code">// 比如登录, 在登录的时候出于安全考虑要记录上次登录时间
// 出于商业考虑, 给你推荐商品
class user implements SplSubject {
public $lognum;
public $hobby;
protected $observers = null;
public function __construct($hobby) {
$this->lognum = rand(1, 10);
$this->hobby = $hobby;
$this->observers = new SplObjectStorage();
}
public function login() {
// 操作session
$this->notify();
}
public function attach(SplObserver $observer) {
$this->observers->attach($observer);
}
public function detach(SplObserver $observer) {
$this->observers->detach($observer);
}
public function notify() {
$this->observers->rewind();
while($this->observers->valid()) {
$observer = $this->observers->current();
$observer->update($this);
$this->observers->next();
}
}
}
class secrity implements SplObserver {
public function update(SplSubject $subject) {
if($subject->lognum < 3) {
echo '这是第'.$subject->lognum.'次安全登录';
} else {
echo '这是第'.$subject->lognum.'次登录,异常';
}
}
}
class ad implements SplObserver {
public function update(SplSubject $subject) {
if($subject->hobby == 'sports') {
echo '台湾英锦赛';
} else {
echo '好好学习天天向上';
}
}
}
// 实施观察
$user = new user('sports');
$user->attach(new secrity());
$user->attach(new ad());
$user->login();<!DOCTYPE HTML>
<html>
<head>
<title>colour_blue</title>
<meta name="description" c />
<meta name="keywords" c />
<meta http-equiv="content-type" c />
<style>
div{
margin:10px;
width:500px;
height:200px;
border: 1px solid green;
}
#content {
}
#ad {
}
</style>
</head>
<body>
<h1>观察者模式</h1>
<select name="">
<option value="male">男式风格</option>
<option value="female">女式风格</option>
</select>
<input type="button" value="观察尾部" />
<input type="button" value="别观察尾部了" />
<div>我是内容</div>
<div>我是广告</div>
<div>学习</div>
<script>
// 服务器端
var sel = document.getElementsByTagName('select')[0];
sel.observers = {};
sel.attach = function(key, obj) {
sel.observers[key] = obj;
}
sel.detach = function(key) {
delete this.observers[key];
}
sel.onchange = sel.notify = function(){
for(var key in this.observers) {
this.observers[key].update(this);
}
}
// 客户端
var content = document.getElementById('content');
content.update = function(observer) {
if(observer.value == 'male'){
this.style.backgroundColor = 'gray';
} else if(observer.value=='female'){
this.style.backgroundColor = 'pink';
}
}
sel.attach('content', content);
var ad = document.getElementById('ad');
ad.update = function(observer) {
if(observer.value == 'male'){
this.innerHTML = '汽车';
} else if(observer.value=='female'){
this.innerHTML = '减肥';
}
}
sel.attach('ad', ad);
// 客户端和服务端实现了解耦
// 后面有一个学习区, 如果状态改变了, 学习区也要变化
var study = document.getElementById('study');
study.update = function(observer) {
if(observer.value == 'male'){
this.innerHTML = '学习计算机';
} else if(observer.value=='female'){
this.innerHTML = '学习美容';
}
}
sel.attach('study', study);
//如果想不观察尾部了
function t1() {
sel.atach('study', study);
}
function t2() {
sel.detach('study');
}
</script>
</body>
</html>.html
<!DOCTYPE HTML>
<html>
<head>
<title>colour_blue</title>
<meta name="description" c />
<meta name="keywords" c />
<meta http-equiv="content-type" c />
<style>
div{
margin:10px;
width:500px;
height:200px;
border: 1px solid green;
}
#content {
}
#ad {
}
</style>
</head>
<body>
<h2>责任链模式举报过程</h2>
<form action="10.php" method="post">
<select name="jubao">
<option value="1">粗口</option>
<option value="2">黄赌毒</option>
<option value="3">分裂国家</option>
</select>
<button type="submit">举报</button>
</form>
</body>
</html>
.php
<?php
header('Content-type: text/html; charset=utf-8');
//版主
class board {
protected $power = 1;
protected $top = 'admin';
public function process($lev) {
if($lev <= $this->power) {
echo '版主删贴';
} else {
$top = new $this->top;
$top->process($lev);
}
}
}
class admin {
protected $power = 2;
protected $top = 'police';
public function process($lev) {
if($lev <= $this->power) {
echo '管理员封账号';
} else {
$top = new $this->top;
$top->process($lev);
}
}
}
class police {
protected $power;
protected $top = null;
public function process($lev) {
echo '抓起来';
}
}
$lev = $_POST['jubao']+0;
$judge = new board();
$judge->process($lev);.html
<!DOCTYPE HTML>
<html>
<head>
<title>colour_blue</title>
<meta name="description" c />
<meta name="keywords" c />
<meta http-equiv="content-type" c />
<style>
div{
margin:10px;
width:500px;
height:200px;
border: 1px solid green;
}
#content {
}
#ad {
}
</style>
</head>
<body>
<h2>面向过程完成举报过程</h2>
<form action="09.php" method="post">
<select name="jubao">
<option value="1">粗口</option>
<option value="2">黄赌毒</option>
<option value="3">分裂国家</option>
</select>
<button type="submit">举报</button>
</form>
</body>
</html>
.php
<?php
header('Content-type: text/html; charset=utf-8');
$lev = $_POST['jubao'];
//版主
class board {
public function process() {
echo '版主删贴';
}
}
class admin {
public function process() {
echo '管理员封账号';
}
}
class police {
public function process() {
echo '抓起来';
}
}
if ($lev == 1) {
$judge = new board();
$judge->process();
} elseif($lev==2) {
$judge = new admin();
$judge->process();
} elseif($lev==3) {
$judge = new police();
$judge->process();
}
// 处理的不够优雅, 现在还是面向过程的写法, 面向过程和面向对象混合了
// 如果以后在两个等级中间要添加一个等级应该怎么办.html
<!DOCTYPE HTML>
<html>
<head>
<title>colour_blue</title>
<meta name="description" c />
<meta name="keywords" c />
<meta http-equiv="content-type" c />
<style>
div{
margin:10px;
width:500px;
height:200px;
border: 1px solid green;
}
#content {
}
#ad {
}
</style>
</head>
<body>
<h2>策略模式 和工厂方法的区别只是在逻辑上的区别, 也叫聚合</h2>
<form action="11.php" method="post">
<input type="text" name="op1" />
<select name="op">
<option value="add">+</option>
<option value="sub">-</option>
<option value="mul">*</option>
<option value="div">/</option>
</select>
<input type="text" name="op2" />
<button type="submit">计算</button>
</form>
</body>
</html>
.php
<?php
/**
* Created by PhpStorm.
* User: michaeldu
* Date: 15/7/15
* Time: 上午12:11
*/
interface Math {
public function calc($op1, $op2);
}
class MathAdd implements Math{
public function calc($op1, $op2)
{
return $op1 + $op2;
}
}
class MathSub implements Math{
public function calc($op1, $op2)
{
return $op1 - $op2;
}
}
class MathMul implements Math{
public function calc($op1, $op2)
{
return $op1 * $op2;
}
}
class MathDiv implements Math{
public function calc($op1, $op2)
{
return $op1 / $op2;
}
}
//封装一个虚拟计算器, 统一计算接口
class CMath {
protected $calc = null;
public function __construct($type) {
$calc = 'Math'. ucfirst($type);
$this->calc = new $calc();
}
public function calc($op1, $op2) {
return $this->calc->calc($op1, $op2);
}
}
$type = $_POST['op'];
$cmath = new CMath($type);
echo $cmath->calc($_POST['op1'], $_POST['op2']);// 装饰器模式 decorator
class article {
protected $content;
public function __construct($content)
{
$this->content = $content;
}
public function decorator() {
return $this->content;
}
}
$art = new article("好好学习");
echo $art->decorator();
// 文章需要小编加摘要
class BianArticle extends article {
public function summary() {
return $this->content.'小编加了摘要';
}
}
$art = new BianArticle('好好学习');
echo $art->summary();
// 又请了SEO人员, 要对文章进行description处理...
class SEOArticle extends BianArticle {
public function seo() {
//...
}
}
// 又有了广告部
class ADArticle extends SEOArticle {
// 层次越来越深, 目的却只是给文章加各种内容
}// 装饰器模式做文章修饰功能
class BaseArt {
protected $content;
protected $art;
public function __construct($content) {
$this->content = $content;
}
public function decorator() {
return $this->content;
}
}
//编辑文章摘要
class BianArt extends BaseArt {
public function __construct(BaseArt $art) {
$this->art = $art;
}
public function decorator() {
return $this->content = $this->art->decorator() . '小编摘要';
}
}
// SEO
class SEOArt Extends BaseArt {
public function __construct(BaseArt $art) {
$this->art = $art;
}
public function decorator() {
return $this->content = $this->art->decorator() . 'SEO关键词';
}
}
$b = new SEOArt(new BianArt(new BaseArt('天天向上')));
echo $b->decorator();
$b = new BianArt(new SEOArt(new BaseArt('天天向上')));
echo $b->decorator();
// 装饰的先后顺序可以随便换, 新增多少个装饰者都很方便
// 基类负责创建对象
// 子类负责装饰// 适配器模式
// 服务器端代码
class weather {
public static function show() {
$today = [
'tep' => 28,
'wind' => 7,
'sun' => 'sunny',
];
return serialize($today);
}
}
// 客户端调用
$weather = unserialize(weather::show());
echo '温度: ',$weather['tep'],'<br />';
echo '风力: ',$weather['wind'],'<br />';
echo 'sun: ',$weather['sun'],'<br />';
// 来了一批手机上的java客户端 , 不认识PHP的串化行后的字符串, 怎么办?
// 把服务器端代码改了? 旧的客户端会受影响
// 旧的类和函数都不让修改, 如何来进行扩展
// 增加一个适配器
class AdapterWeather extends weather {
public static function show() {
//拿到旧数据
$today = parent::show();
// 然后开始转换
$today = unserialize($today);
$today = json_encode($today);
return $today;
}
}
// ==== java, python再来调用就不怕了, 通过适配器调用
$weather = AdapterWeather::show();
$w = json_decode($weather);
echo '温度: ',$w->tep,'<br />';
echo '风力: ',$w->wind,'<br />';
echo 'sun: ',$w->sun,'<br />';
// 没有修改旧的方法, 这样就没有影响旧的客户端
// 没有修改旧的类, 说明没有违反开闭原则// 桥接模式 bridge 尝试
// 论坛给用户发信息, 可以是站内短信, email, 手机
// 本来只需要发站内短信, 后来又需要发email
// 一个类只做一件事, 我们把他做成一个接口或者抽象类, 具体的发送由具体的子类实现
interface msg {
public function send($to, $content);
}
class zn implements msg {
public function send($to, $content)
{
echo '站内信给', $to, ' 内容是: ', $content;
}
}
// 有一天要改造, 要发email
class email implements msg {
public function send($to, $content)
{
echo 'email给', $to, ' 内容是: ', $content;
}
}
// 后来要发短信
class sms implements msg {
public function send($to, $content)
{
echo '短信给', $to, ' 内容是: ', $content;
}
}
// 后来内容也丰富了, 分普通, 加急, 特急
// 子类就爆炸了, 像数据的三范式一样, 如果完全遵循解耦是不行了
/*
class zncommon extends zn;
class znwarn extends zn;
class zndanger extends zn;
class emailcomm extends email;
class emailwarn extends email;
class emaildanger extends email;
....
*/
/**
* 思考:
* 信的发送方式是一个变化因素
* 信的紧急程度是一个变化因素,
* 为了不修改父类, 只好考虑2个因素的组织, 不停产生新类....
*/
abstract class info {
protected $send = null;
public function __construct($send) {
$this->send = $send;
}
abstract public function msg($content);
public function send($to, $content){
$content = $this->msg($content);
$this->send->send($to, $content);
}
}
class zn {
public function send($to, $content) {
echo '站内给: ', $to, '内容是: ', $content;
}
}
class email {
public function send($to, $content) {
echo 'email给: ', $to, '内容是: ', $content;
}
}
class sms {
public function send($to, $content) {
echo 'sms给: ', $to, '内容是: ', $content;
}
}
class commoninfo extends info{
public function msg($content) {
return '普通'. $content;
}
}
class warninfo extends info{
public function msg($content) {
return '紧急'.$content;
}
}
class dangerinfo extends info{
public function msg($content) {
return '紧急'.$content;
}
}
// 用站内发普通信息
$commoninfo = new commoninfo(new zn());
$commoninfo->send('小明', '吃饭了');
//给小刚发紧急手机短信消息
$dangerinfo = new dangerinfo(new sms());
$dangerinfo->send('小刚', '失火了');
// 本来需要3x3个类
// 现在只需要3+3个类了
// 现在耦合了, view中不写逻辑, 数据库三范式, 老有相同的字段, 为了速度, 之前的设计模式都是在解耦, 现在反而增加了耦合, 是为了防止子类爆炸以上就介绍了PHP常用设计模式单例, 工厂, 观察者, 责任链, 装饰, 策略,适配,桥接模式,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号