资讯专栏INFORMATION COLUMN

Learning PHP —— 设计模式 | Chap2:设计模式与UML

senntyou / 1907人阅读

摘要:设计模式设计模式基本原则设计原则按接口而不是按实现来编程按接口而不是按实现编程是指,要将变量设置为一个抽象类或接口数据类型的实例,而不是一个具体实现的实例。例如父类的一个改变会逐级向下传递给子类实现,这可能会影响子类使用的某个算法。

设计模式 设计模式基本原则

设计原则 ① : 按接口而不是按实现来编程

按接口而不是按实现编程是指,要将变量设置为一个抽象类或接口数据类型的实例,
而不是一个具体实现的实例。这样可以将设计与实现解耦合。
有些语言变量声明包含数据类型,例如在一个强类型语言中可以有以下声明:

如果没有强类型机制,可以利用代码提示保证按接口编程,以上一节写过的一段代码为例

doInterface($apple);
        $this->doInterface($book);
    }
    function doInterface(IProduct $product){
    //这里的IProduct $product就是一种类型提示,方法类型提示为接口IProduct
    //无论程序变得多复杂都没关系,只要保证接口
    //就可以做出任意的修改和增补,不会破坏程序的其它部分
        echo $product->apples();
        echo $product->books();
    }
}
$worker = new useProduct();
?>

设计原则 ② : 应当优先选择对象组合而不是类继承

有的OOP程序猿认为对象重用就等同于继承,一个类可以有大量属性和方法,扩展这个类就可以重用所有那些对象元素,而不用重新编写代码。可以扩展类,再增加必要的新属性和方法。下面将举一个例子说明对象组合和类继承之间的区别。

首先是继承的代码

sum = ( $first + $second );
        return $this->sum;
    }
    public function simpleDivide($divided, $divisor){
        $this->quotient = ( $dividend / $divisor);
        return $this->quotient;
    }
}
?>
textOut = (string)$num;
        return $this->textOut;
    }
    public function addFace($face,$msg){
        $this->fullFace = "" . $face . " : " .$msg;
        return $this->fullFace;
    }
}
?>
added = $family->simpleAdd(40,60);
        $this->divided = $family->simpleDivided($this->added,25);
        $this->textNum = $family->numToText($this->divided);
        $this->output = $family->addFace("Your results",$this->textNum);
        echo $this->output;
    }
}
$worker = new ClientInherit();
?>

下面是组合,Client类使用两个不同的类,分别包含两个方法,DoMath类等同于继承例子中的父类,所以首先是DoText类

textOut = (string)$num;
        return $this->textOut;
    }
    public function addFace($face,$msg){
         $this->fullFace = "" . $face . " : " .$msg;
        return $this->fullFace;
    }
}
?>
added = $useMath->simpleAdd(40,60);
        $this->divided = $useMath->simpleDivide($this->added,25);
        $this->textNum = $useText->numToText($this->divided);
        $this->output = $useText->addFace("Your results",$this->textNum);
        echo $this->output;
    }
}
?>

Client类必须包含多个类,看起来更胜一筹,不过在较大的程序中,组合可以避免维护多个继承层次上的各个子类,而且还可以避免可能导致的错误。例如父类的一个改变会逐级向下传递给子类实现,这可能会影响子类使用的某个算法。
要避免使用继承形成一长串子类、孙子类、曾孙子类,设计模式方法建议使用浅继承。

设计模式的组织
设计模式是按照作用和范围来组织的

设计模式按作用可以分为以下3类

创建型

顾名思义,就是用来创建对象的模式,更确切地讲,这些模式是对实例化过程的抽象
如果程序越来越以来组合,就会减少对硬编码实例化的依赖,而更多地以来于一组灵
活的行为,这些行为可以组织到一个更为复杂的集合中,创建型模式提供了一些方法
来封装系统使用的具体类的有关知识,还可以隐藏实例创建和组合的相关信息

结构型

这些模式所关心的是组合结构应当保证结构化。结构型类模式采用继承来组合接口或实现结构型对象模式则描述了组合对象来建立新功能的方法。了解结构型模式对于理解和使用相互关联的类(作为设计模式中的参与者)很有帮助

行为型

到目前为止,绝大多数模式都是行为型对象,这些模式的核心是算法和对象之间职责的分配。这些设计模式描述的不只是对象或类的模式,它们还描述了类和对象之间的通信模式

设计模式按范围可以分为以下2类


在两类范围中,第一类范围是类。这些类模式的重点在于类及其子类之间的关系,类模式中的关系是通过继承建成

对象
尽管大多数设计模式都属于对象范围,不过与类范围中的那些模式一样,很多模式也会使用继承。对象设计模式与类模式的区别在于,对象模式强调的是可以在运行时改变的对象,因此这些模式更具动态性。

设计模式作用、范围和变化

设计模式与框架有什么不同
与框架相比,设计模式是体系结构中更小的元素,也更为抽象,另外设计模式没有框架那么
特定。因此,设计模式更可重用,也比框架灵活。
框架的有点与模板有些类似:它们更有指示性,可以更清楚地指示所解决问题的结构。为了
提供这种易用性,它们不得不放弃了体系结构的灵活性。如果使用框架,构建应用会快得多,
但是所构建的应用会受到框架本身的约束。框架可以包含面向对象结构,通常框架是分层的,
每一层处理更大设计中的一个方面。框架的一些特性在设计模式中也有体现,不过,设计模
式没有框架那么特定和具体,也没有那么庞大
UML
概念:UML(the Unified Modeling Language——统一建模语言),引入了一个强大的
图形化的语法来描述面向对象系统
类图 1.描述类
类是类图的主要部分,类用带有类名的方框来描述。

上图中,图1最先显示的是类的名称,下面两部分是可选的,用于显示类名之外的信息。
可以发现图1已经足够描述一些类,并非总要在类图中显示每个属性和方法,甚至不需要
显示每个类

通常用斜体的类名(图2),或者增加{abstract}到类名下(图3)来表示该类是抽象
类。 第一种方法比第一种方法常用,但是当你做笔记时第二种方法更有用

接口定义的方式和类相同,但接口必须使用一个衍型(UML的一个扩展),如楼下所示

2.属性

一般来说,属性用于描述一个类的属性,属性直接列在类名下面的格子中,如楼下所示

属性前面的符号表示该属性可见性的级别或者是访问控制

冒号用于分隔属性名和它的类型及默认值(默认值为可选项,可以不提供)
Again:只要提供必要的信息,不需要所有细节

3.操作

操作用于描述类方法,操作和属性使用了相似的语法

(1)可见性符号放在方法名之前
(2)参数列表包含在括号之中
(3)方法如果有返回类型的话,用冒号来描述
(4)参数用逗号来分隔,并且遵守属性语法
(5)参数名和它的数据类型间用冒号分隔

如下图所示

4.描述继承和实现

继承关系用从子类到父类的一条线来表示,线的顶端有一个空心闭合箭头

UML用"实现"来描述接口和实现接口的类之间的关系,如果ShopProduct类实现了Chargeable接口,就可以加入类图中,如图所示

5.关联

一个类的属性保存了对另一个类的一个实例或多个实例的引用时,就产生了关联
下图中为辆各类建立模型,并创建类之间的关联,图中指出Teacher对象拥有一个或多个对Pupil对象的引用,或者Pupil对象拥有一个或多个对Teacher对象的引用

我们可以用剪头来描述关联的方向,如果Teacher类拥有Pupil类的一个实例,但是Pupil类并没有Teacher类的实例,那我们可以让关联剪头从Teacher类指向Pupil类,称为"单向关联"

如果两个类剪互相拥有对方的引用,可以用一个双向剪头来描述这种"双向关联"关系

也可以在关联中指定一个类的实例被其它类引用的次数,可以通过把次数或者范围放在每个类旁边来说明。用星号(*)表示任意次数,如下图所示,Teacher对象拥有零个或多个Pupil对象

6.聚合和组合
都描述了一个类长期持有其它类的一个或多个实例的情况,通过聚合和组合,被
引用的对象实例成为引用对象的一部分。
聚合关系用一条以空心菱形开头的线来说明,如下图所示,定义了两个类,
SchoolClass和Pupil, SchoolClass类聚合了Pupil
(意思就是学生组成了班级,如果我们要删除一个学校类,不需要同时删除)

组合是一个更强的关系,在组合中,被包含对象只能被它的容器所引用,当容器删除
时,她应该也被删除,组合关系用类似聚合关系的方式描述,但它的菱形是实心的
下图中,Person类持有对SocialSecurityData对象的引用,而SocialSecurityData
对象实例属于包含它的Person对象

7.描述使用
使用:即依赖关系,并非类之间的长久关系
下图中,Report类使用了ShopProductWriter对象,这种使用关系由一条连接两个类
的虚线和开放剪头表示。Report类没有把ShopProductWriter保存为类中的属性,
ShopProductWriter对象则将一组ShopProduct对象作为属性

8.使用注解
注解:解释类处理任务的过程(类图只能捕捉系统结构)
如下图,Report对象使用了ShopProductWriter,但是不知道具体如何实现,
我们使用了注解来补充说明

如图所示,注解由一个这叫的方框组成,通常包含伪代码片段
时序图
时序图是基于对象而不是基于类的,用于为系统中过程化的行为建模。

如下,为Report对象输出产品数据的过程建模,从左到右展现了系统的参与者
我们值使用类名来标记对象,如果图中有同一个类的多个对象实例在独立工作,
可以使用label:class(例如product1 : ShopProduct)格式来包含对象名

下图我们从上到下展示了该过程每个对象的生命周期

垂直的虚线是生命线,展示了系统中对象的生命周期,生命线上的矩形说明了过程中的
焦点,即某个对象的激活期。
显示对象间传递的消息,这个图才更容易被看懂,如下

箭头表示消息从一个对象传递到另一个对象,返回值一般不写。
每个消息都用相关的方法调用来标记,例如方括号说明一个条件,像
{okToPrint}
write()
只有在一定条件下write才会被执行
星号用于表示一个重复的操作,可以在方括号中进一步说明
*{for each ShopProduct}
write()

该图含义:Report对象获得一个来自ProductStore对象的ShopProduct对象列表。
Report对象传递这个ShopProduct列表给一个ShopProcuctWriter对象,而
ShopProductWriter存放了对ShopProduct对象的引用(虽然我们只能从图中推断
出折点)ShopProductWriter对象为它引用的每个ShopProduct对象调用ShopProduct::
getSummaryLine(),并添加执行结果到最终的输出结果中



本文笔记参考书籍:
《深入PHP:面向对象、模式与实践》第4章
《Learning-PHP设计模式》第4章

下节:Chap3:创建型设计模式————工厂方法设计模式

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21227.html

相关文章

  • PHP面试常考之设计模式——建造者模式

    摘要:你好,是我琉忆,程序员面试笔试系列图书的作者。建造者模式介绍建造者模式又名生成器模式,是一种对象构建模式。表示被构造的复杂对象。创建该产品的内部表示并定义它的装配过程。 你好,是我琉忆,PHP程序员面试笔试系列图书的作者。 本周(2019.3.11至3.15)的一三五更新的文章如下: 周一:PHP面试常考之设计模式——工厂模式周三:PHP面试常考之设计模式——建造者模式周五:PHP面...

    alexnevsky 评论0 收藏0
  • 通俗易懂的设计模式

    摘要:面向对象设计模式通常以类别或对象来描述其中的关系和相互作用,但不涉及用来完成应用程序的特定类别或对象。里氏代换原则里氏代换原则是面向对象设计的基本原则之一。 通俗易懂的设计模式 零、使用 1、安装 2、测试 一、什么是设计模式 二、设计模式的类型 三、设计模式的六大原则 四、UML类图 1、看懂UML类图 2、解释 五、资料 前言:花了一些时间再次熟悉了一遍...

    wuyangnju 评论0 收藏0
  • Learning PHP —— 设计模式 | Chap1:浅谈设计模式中的OOP

    摘要:而哈士奇区别于普通狗,又有新的特征逗比,爱捣乱为了保证类之间的松绑定,通常会继承抽象类,而且是浅继承只有一层子类。如果知道所有类都会共享一个公共的行为实现,就使用抽象类,并在其中实现该行为。 为什么使用OOP OOP是一个模块化的过程,目的是为了把复杂问题简单化,一个模块解决一个复杂问题的某一个方面,即一个类应当只有一个职责 OOP区别于顺序式编程与过程式编程,在于: 1.顺序编程...

    SunZhaopeng 评论0 收藏0
  • php uml图生成并能支持processon导入

    摘要:它是一款全自动图生成器,支持。但是图并不方便操作。因为经常使用来做图,所以如果能生成一个可以导入到的文件那就更好了。文件支持导入文件,那文件到底是什么样子的是导出时,生成的图片,包含各个元素。导入主要看的是。 项目需要画uml图,手写浪费时间,于是就搜了一些相关的工具来生成它。有php插件phpumd等等。发现了一个简单易用的工具,那就是phuml。 Phuml 它是一款全自动uml图...

    weapon 评论0 收藏0
  • App后台api开发前的准备

    摘要:负责从拉取数据源,把数据源分词,建立索引搜索模块工作流程如下模块从中拉取数据模块用经过中文分词后的数据建立索引客户端向模块发起搜索请求模块查找索引中的数据模块得到索引中符合要求的数据的等数据把数据返回给客户端 (整理自《App后台开发运维和架构实践》 作者:曾健生) 一、从业务逻辑中提炼API接口 此过程可分为六个阶段: 业务逻辑思维导图 功能——业务逻辑思维导图 基本功能模块关系 ...

    yzzz 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<