欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

浅述PHP设计模式(5)

程序员文章站 2022-03-02 16:59:19
...

二、结构型模式——类与方法的调用控制问题

    Adapter(适配器):将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。   
    实现方式:创建一个Adapter,对构造函数传入的类作为实际操作类。Adapter通过代码对操作类各个方法的调用,实现调用方所需要的方法。
    可以看出,使用这一具类的场景,是具体代码的接口已经确定。并且核心代码的调用方的接口也已确定。但二者之间不是相互调用关系,适配器是协助建立这样的调用关系。
    总结:通过将目标对象作为参数传给Adapter,通过Adapter向调用方提供所需要的接口。
    选择模式:方法与代码的组合。方法调用的一致性。本地使用唯一方法调用,外部实现代码配合

    Bridge(桥接):将抽象部分与它的实现部分分离,使它们都可以独立地变化。
    实现方式:具体的代码中,当使用抽象类应对可能的变化时,会遇到这样的情况:如果具体的实现完全采用继承的方法,那么,具体的实现类就不能再用作它用。亦即继承是静态绑定的。如果这些具体的类还有它用,则需要丢开继承,而使用桥接进行解耦。
    这时,我们可以在抽象类的子类的构造函数中增加实现类的参数。从而在这个子类中根据参数创建指定的实现类。即抽象类的子类聚合指定的实现类。
    由此可见:Bridge对象通过抽象类的子类的构造函数获得参数后,通过聚合参数中指定的类,同时创建对应的拥有相关方法的子类(实现类),从而在聚合的类与相关子类(实现类)之间架设了一座桥。
    总结:通过构造函数中的参数实现子类与另一类的组合。
    选择模式:类与类的组合。多层继承会产生一个迪卡尔积的类,这样类太多了。而且,代码会出现重复,即相同代码在不同文件中出现多次。如果只是组合,则Bridge实现了二维到多维的选择。

    Composite(组合):将对象组合成树型结构以表示“部分-整体”的层次结构。Composite使得客户对单个对象和复合对象的使用具有一致性。
    组合模式适用于,单数对象与复数对象行为,或拥有的函数接口是完全相同的,只有具体的算法不一致。如果不是这种情况,则应当不使用这一模式。
    实现方式:单个模式的对象与复合对象(其中数量有多个)均继承同一的抽象类,实现完全相同的接口。
    总结:将复数与单数类一致起来
    选择模式:单数与复数的一致性。在选择时无需再区分复数还是单数。

    Decorator(装饰):动态地给一个对象添加一些额外的职责。就扩展功能而言,Decorator模式比生成子类方式更为灵活。
    如果直接继承,则如果有多少父类,就会有多少子类。而现在面临的父类是:已经是从抽象类或接口生成的子类了。而我们有可能要给其中一部分子类添加一些方法,但不一定是全部子类。就是如此,如果我们使用继承,也会生成一批新的子类。
    实现方式:解决上面的问题是,建一个装饰器类,让要动态增加方法的类作为装饰器类构造函数的参数。这样,我们就可以动态为需要增加新方法的类增加新的方法。所以,新的Decorator类把原来的类作为属性,并增加所需的方法。可见,这里,要增加的方法,是具体的代码。
    总结:将原来的子类与新方法组合起来,实现多对多组合。
    选择模式:子类与方法的组合

    Facade:为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
    当一个类,需要对一群类进行操作,而这些操作本身会因被操作的类的变化而有所变化。如果我们将这些操作直接写在操作者类中,则违反了LoD。如果我们用一个类,向操作者类提供一个操作面板,这样就打破了这种直接的紧耦合关系。这样,调用者直接调用面板类,而不需要更多的调用算法的细节。我们可以看出,这里,具体的代码则指面板中调用到的系统类。核心代码则是调用者。
    实现方式:用一个类抽象出对某一子系统部分的操作,并实现相关的代码。
    总结:合并固定的一组操作到前置的类中。
    选择模式:不同类的不同方法选择,并组合成代码,成为Facade类的方法。


    Flyweight(享元):运用共享技术有效地支持大量细粒度的对象。
    中文的享元这个名字要比英文的Flyweight(蝇量)要易于理解。但这两个名字却叙述了这个模式的两个方面。这个模式实际是工厂模式的另一变体。但工厂模式是直接用来使用的。这里是把目标类作为共享对象给大家使用的。所以,享元模式仍属于结构型模式。做不到结构型这一点,那就成工厂模式了。
    实现方式:需要一个享元工厂管理共享的资源,把所有共享的资源的生产全部交给个享元工厂,这也就是说,享元工厂类中存在所有用于生产的方法。其中包括保存细粒度对象的属性(数组类型),以及获取细粒度对象的方法,通常是工厂方法。
    整个结构则是,我们有为细粒度对象定义的抽象类或接口,有由此继承生成的具体的类。有一个类,用来负责对这一些对象的生产。同时保存或存储这些对象,即对象的存储器。有一个类,是一个统一的接口。用来对所有这些对象进行访问。
    总结:做一个对象的存储器。
    选择模式:从大量共享对象中选择。统一选择接口。
    使用享元的特殊场景是:一个应用程序使用了大量的对象。完全由于使用大量的对象,造成很大的存储开销。对象的大多数状态都可变为外部状态。如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
    享元与工厂的最大的不同是,工厂创建的对象是专用的,而享元则是共享的。同时,WEB方式下,不限于同一请求下的享元,同时可以多请求下使用享元,这种模式最有名的是DRYSQL。当然,也可以不用享元实现共享,但则需要大量的单件模式,从而造成内存的开销。而享元则是节省内存资源的最好的方法。

    Proxy:为其他对象提供一个代理以控制对这个对象的访问。
    实现方式:在实际要使用的类“前端”再加一个类,用以完成相关的控制。这里,可能会与Adapter(适配器)模式相混,其实二者的区别在于,适配器模式存在对等关系的。即所用的类,都能够通过结构转换为相同的接口。而代理,则是不同的接口,并且,代理是区分不同的操作访问不同类的不同的方法。二者相联系的只是,二者均是一对多模式。但是,Adapter(适配器)是访问所有类的相同的方法的组合。代理则是访问不同类的不同的方法的组合。
    总结:对类方法调用增加前置预处理。成为中转代理类。
    选择模式:对调用进行选择与控制。


总结:结构型模式中的所有模式,是用来解决由于我们使用了SOLID原则,从而使用了所有前述的创建型模式之后产生的一切“不良后果”,当然,不用SOLID原则,一样也会出现或遇上这些问题。这些“不良后果”是类与类之间,关键是核心代码调用具体代码时的不能调用的问题,而解决方法,实际是根据具体问题,添加不同的类作为中间件。
通过这一章节,我们发现,实际上,对于设计模式的代码分析,不外乎两个方面:第一,谁是核心,谁是具体问题。即分清:变与不变的。第二则是,分清调用关系。

(待续)