设计模式学习


开闭原则

在面向对象编程领域中,开闭原则规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查,单元测试以及诸如此类的用以确保产品使用质量的过程。遵循这种原则的代码在扩展时并不发生改变,因此无需上述的过程。

有具体代码 可查看下面链接
https://www.cnblogs.com/Mishell/category/1631078.html


1:学习设计模式的意义

学习设计模式的意义
1:更深入的理解面向对象的思想.
2:有利于开发出扩展性强的程序
3:面试时的重要考察方面

2:设计模式的概念

在软件开发过程中,经常出现的典型场景的典型解决方案,称为设计模式

生活中也有很多设计模式:
象棋招法,泡妞思路,
电影悬疑等等

2.1:动手造几个设计模式

典型场景: 同学聚会
典型问题: 问你工资
典型解决: ?? 就那样吧 还行

典型场景: QQ,屌丝,女神
典型问题: 女神,还没睡?
典型解决: ?? 洗澡 呵呵

如何学习设计模式?
典型场景–>典型问题–>典型解决办法

3:先说多态

为什么先说多态?
答: 多态相对封装与继承,理解稍微复杂一些.
更重要的是,
通过PHP,Java多态的不同体现,体会静态语言与动态语言的巨大差异

–而这个差异巨大,影响到设计模式.
对于动态语言,不可照搬java,C++中的设计模式

3.1:多态

多态(Polymorphism) 是一个生物学上的概念,
指同一特种的多种表现形态.
如:西伯利亚虎一般重210-260公斤,而孟加拉虎一般180-230公斤

在面向对象中,指某种对象实例的不同表现形态.

多态特点,在静态语言中体现的更为明显.

3.2:老虎爬树

西伯利亚虎不能爬树
孟加拉虎可以爬树

那么老虎,到底能否爬树?

[
请看java与PHP演示
体会静态与动态的巨大差异
]

4:简单工厂模式 Factory

4.1:分析问题

代码执行没问题,调用没问题!

但是:
你(客户端,调用者)怎么知道我有个DBmysql类, 和 DBMysqli类?

1:客户端应该只看到接口,不应该知道接口的实现.
体现封装隔离原则.

2:无论客户端,而是后端,都依赖于抽象接口,而非依赖于具体

4.2:解决问题

添加一个工厂,由工厂负责创造对象,并返回

4.3:用简单工厂后

4.4:用简单工厂的真正意义

看似仅仅是把创建对象的过程包装了一下,真正的变化在于”面向接口”,”隔离封装”,
客户端只知接口,不知具体实现.
后端的实现,只知接口,不管前端谁调用

4.5:简单工厂需改进之处

如果新增PDO方式,是否还要改Factory?
修改if/else分支?

违反开闭原则.

另:这个工厂如果分支足够多,能帮你创建所有的类,形成”万能工厂”,面向对象设计中,不推荐一个类的功能过多.

我们可以把有相关关系的产品交由一个工厂生产

开闭原则

1988年,勃兰特·梅耶(Bertrand Meyer)在他的著作
《面向对象软件构造(Object Oriented Software Construction)》中提出了开闭原则,
它的原文是这样:“Software entities should be open for extension,
but closed for modification”。
翻译过来就是:“软件实体应当对扩展开放,对修改关闭”。

通俗的说: 添加新类/接口等进来行,修改不行.

5.0:工厂方法 Factory Method

工厂方法中,一个工厂生产多个零件,但零件的共同特点是–属于一个产品.

即 此工厂可以生产产品,而非单独的对象

6:单例模式 singleton 场景回放

6.1:问题–如何确保只制造一个对象?

1:对象的产生,需要new或者clone
2:防止产生过多的对象,要防止new和clone
3:综上,没有对象时,允许new,并把对象缓存.
下次直接返回该对象

6.2:解决效果

6.3:模式解析

1:我学java时听说有”懒汉式”和”饿汉式”单例模式
答:PHP的属性不支持表达式,不支持”饿汉式”

2:php的单例,仅指进程中单例,不似java,在整个内存中单例

7:观察者模式 Observer

7.1:一般的思路

1:判断选中的值
2:顺序下来,根据值,修改内容区域
3:再修改广告区域.

if(v == ‘男’) {
内容区背景变灰
广告区内容变成男人话题
} else if(v == ‘女’){
内容区背景变粉
广告区内容变成女人话题
}

问题在哪儿?
1:让你选择时引起3个区域的变化,
是否要修改if/elseif部分

2:如果选择女性样式,但不要变粉,现在流行变紫色,是否又要修改if elseif部分?

问题在于: 控制逻辑与被操作对象耦合严重.

7.2:解决办法

我们让div对象观察select的变化,select变化,就会通知道这两个对象.
并引起这2个对象的变化,实现观察者模式

7.3:解决效果

select对象负责attach,detach,notifyObservers,与具体的对象变化解耦

8:职责链模式 chain of resionbility

8.1:一般做法

POST发送数据,
PHP接收到数据,判断举报的级别.

if(粗口) {
启动转发给版主的流程
} else if(黄赌毒) {
启动转发给管理员的流程
} else {
启动转发给公安的流程
}

问题在哪儿:
1:如果新增了举报级别,
要改if else 代码段.

2:如果流程内部有改动,也要到if else 代码段来操作.

总结:逻辑与执行操作的对象耦合严重.

8.2:解决办法-职责链模式

每个对象,储存着对自己上级的引用,如果自己处理不了,交给上一级.

8.3:解决之后-职责链模式

如下,只需要提交给版主即可,版主处理不了,会自动提交给上一级,直到处理完毕.

9:策略模式

9.1:一般的思路

根据传递的参数不同,进行加减乘除运算

思考: 如果想增加取模运算又如何操作?

想一想简单工厂方法,是否有些相似? 又有哪些不同?

通过接口,隔离封装
通过继承,适应变化

工厂模式,我们着眼于得到对象,并操作对象,
策略模式,我们着重得到对象某方法的运行结果

9.1:策略的实现 strategy

context对象
持有计算对象
并计算结果
直接返回

10:装饰器模式 decorator

这是一篇帖子

帖子的内容我写好了,
三个部门的人员想控制他.
编辑组要添导读文字
审核组要去敏感字
市场部想在末尾加点广告
我只是一篇帖子,由你们来处置吧

分析:三部分都操作该文章,
最先是编辑组,继承该文章并添加了导读方法
审核组来了,继承了该文章,添加去敏感字方法
市场部,继承该文章,添加广告方法


继承的层次越来越深

能否不继承,动态的增加对象的功能?

10.1:引入装饰器模式

11 适配器模式

将各种截然不同的函数接口封装成统一的API。
<?php
header(“Content-type:text/html;charset=utf-8”);

// 适配器模式

/**

  • 查看天气接口
  • /
    class Tianqi
    {
    public static function show(){
       $arr = array('tem'=>28,'wind'=>8,'sun'=>'windy','weekday'=>"周三");
       return serialize($arr);
    
    }
    }

//php客户端调用
$b = unserialize(Tianqi::show());
echo “时间:”.$b[‘weekday’].”
“;
echo “温度:”.$b[‘tem’].”
“;
echo “风力:”.$b[‘wind’].”
“;
echo “太阳:”.$b[‘sun’].”
“;

// 突然来了一批Java程序员,需要获取天气接口数据,但是他们不识别序列化后的数据,这时候应该怎么办呢?

/**

  • 增加适配器
  • /
    class ADdapterTianqi extends Tianqi
    {
    public static function show()
    {
       $str = parent::show();
       $arr = unserialize($str);
       return json_encode($arr);
    
    }
    }

// 适配器访问数据
echo “

适配器访问数据:
“;
$b = json_decode(ADdapterTianqi::show(),true);
echo “时间:”.$b[‘weekday’].”
“;
echo “温度:”.$b[‘tem’].”
“;
echo “风力:”.$b[‘wind’].”
“;
echo “太阳:”.$b[‘sun’].”
“;

12桥接模式

集成的话 就是NxN个类

如果是桥接 就是 N+N个类

send = $send; } abstract function msg($content); function send($to, $content){ $content = $this->msg($content); $this->send->send($to, $content); } } /** * 普通信 */ class ZnMsg { public function send($to, $content) { echo "给".$to."发送站内信:
".$content; } } /** * email信 */ class EmailMsg { public function send($to, $content) { echo "给".$to."发送Email:
".$content; } } /** * sms信 */ class SmsMsg { public function send($to, $content) { echo "给".$to."发送短信:
".$content; } } // 内容分为普通,加急,特急三种程度 /** * 普通 */ class CommonInfo extends msg { public function msg($content) { return "普通:".$content."
"; } } /** * 加急 */ class WarnInfo extends msg { public function msg($content) { return "加急:".$content."
"; } } /** * 特急 */ class DangerInfo extends msg { public function msg($content) { return "特急:".$content."
"; } } $DangerInfo = new DangerInfo(new EmailMsg()); $DangerInfo->send('小明','家里着火了'); $WarnInfo = new WarnInfo(new EmailMsg()); $WarnInfo->send('小明','下午参加毕业典礼');

文章作者: Bob
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Bob !
  目录