zoukankan      html  css  js  c++  java
  • 工厂模式

    1、定义

      定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。

      (工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式)

    2、模式分类

      工厂模式根据抽象程度的不同分为三种:简单工厂模式(也叫静态工厂模式)、工厂方法模式、以及抽象工厂模式

    3、主要优点

    • 可以使代码结构清晰,有效地封装变化。在编程中,产品类的实例化有时候是比较复杂和多变的,通过工厂模式,将产品的实例化封装起来,使得调用者根本无需关心产品的实例化过程,只需依赖工厂即可得到自己想要的产品。
    • 对调用者屏蔽具体的产品类。如果使用工厂模式,调用者只关心产品的接口就可以了,至于具体的实现,调用者根本无需关心。即使变更了具体的实现,对调用者来说没有任何影响。
    • 降低耦合度。产品类的实例化通常来说是很复杂的,它需要依赖很多的类,而这些类对于调用者来说根本无需知道,如果使用了工厂方法,我们需要做的仅仅是实例化好产品类,然后交给调用者使用。对调用者来说,产品所依赖的类都是透明的。  

    4、适用场景

            不管是简单工厂模式,工厂方法模式还是抽象工厂模式,他们具有类似的特性,所以他们的适用场景也是类似的。

            首先,作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

           其次,工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。

           再次,由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好。也就是说,当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。

    5、工厂方法模式

          工厂方法模式有四个要素:

    • 工厂接口。工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品。在实际编程中,有时候也会使用一个抽象类来作为与调用者交互的接口,其本质上是一样的。
    • 工厂实现。在编程中,工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现。
    • 产品接口。产品接口的主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性。同样,产品接口也可以用抽象类来代替,但要注意最好不要违反里氏替换原则。
    • 产品实现。实现产品接口的具体类,决定了产品在客户端中的具体行为。

      前文提到的简单工厂模式跟工厂方法模式极为相似,区别是:简单工厂只有三个要素,他没有工厂接口,并且得到产品的方法一般是静态的。因为没有工厂接口,所以在工厂实现的扩展性方面稍弱,可以算所工厂方法模式的简化版,关于简单工厂模式,在此一笔带过。

    实现例子:

    (java)

    #场景是这样的:汽车由发动机、轮、底盘组成,现在需要组装一辆车交给调用者。假如不使用工厂模式,代码如下:
    class Engine {
        public void getStyle(){
            System.out.println("这是汽车的发动机");
        }
    }
    class Underpan {
        public void getStyle(){
            System.out.println("这是汽车的底盘");
        }
    }
    class Wheel {
        public void getStyle(){
            System.out.println("这是汽车的轮胎");
        }
    }
    public class Client {
        public static void main(String[] args) {
            Engine engine = new Engine();
            Underpan underpan = new Underpan();
            Wheel wheel = new Wheel();
            ICar car = new Car(underpan, wheel, engine);
            car.show();
        }
    }

      可以看到,调用者为了组装汽车还需要另外实例化发动机、底盘和轮胎,而这些汽车的组件是与调用者无关的,严重违反了迪米特法则,耦合度太高。并且非常不利于扩展。另外,本例中发动机、底盘和轮胎还是比较具体的,在实际应用中,可能这些产品的组件也都是抽象的,调用者根本不知道怎样组装产品。假如使用工厂方法的话,整个架构就显得清晰了许多。

    interface IFactory {
        public ICar createCar();
    }
    class Factory implements IFactory {
        public ICar createCar() {
            Engine engine = new Engine();
            Underpan underpan = new Underpan();
            Wheel wheel = new Wheel();
            ICar car = new Car(underpan, wheel, engine);
            return car;
        }
    }
    public class Client {
        public static void main(String[] args) {
            IFactory factory = new Factory();
            ICar car = factory.createCar();
            car.show();
        }
    }

      使用工厂方法后,调用端的耦合度大大降低了。并且对于工厂来说,是可以扩展的,以后如果想组装其他的汽车,只需要再增加一个工厂类的实现就可以。无论是灵活性还是稳定性都得到了极大的提高。

     6、抽象工厂模式

    【每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结构】

      当每个抽象产品都有多于一个的具体子类的时候,工厂角色怎么知道实例化哪一个子类呢?比如每个抽象产品角色都有两个具体产品。抽象工厂模式提供两个具体工厂角色,分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化。每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。【多对一

    产品族:

      是指位于不同产品等级结构中,功能相关联的产品组成的家族。一般是位于不同的等级结构中的相同位置上。显然,每一个产品族中含有产品的数目,与产品等级结构的数目是相等的,形成一个二维的坐标系,水平坐标是产品等级结构,纵坐标是产品族。例如蔬菜、水果就是产品等级结构;产地北方、南方就是产品族

     1 <?php
     2 #抽象工厂模式
     3 
     4 #产品等级结构(水果、蔬菜)
     5 #产品水果
     6 interface Fruit{}
     7 #产品蔬菜
     8 interface Vegetable{}
     9 
    10 #产品族(北方、南方)
    11 #一个产品族对应各个产品等级
    12 #北方水果
    13 class NorthFruit implements Fruit
    14 {
    15     //一列操作
    16 }
    17 #南方水果
    18 class SouthFruit implements Fruit
    19 {
    20     //一列操作
    21 }
    22 #北方蔬菜
    23 class NorthVegetable implements Vegetable
    24 {
    25     //一列操作
    26 }
    27 #南方蔬菜
    28 class SouthVegetable implements Vegetable
    29 {
    30     //一列操作
    31 }
    32 
    33 #抽象工厂接口
    34 #有多少个产品等级结构,接口就有多少个声明方法
    35 interface Factory
    36 {
    37     public function createFruit();
    38     public function createVegetable();
    39 }
    40 #实现抽象接口,有多少个产品族就有多少个工厂类
    41 #北方工厂类
    42 class NorthFactory implements Factory
    43 {
    44     public function createFruit()
    45     {
    46         return new NorthFruit();
    47     }
    48 
    49     public function createVegetable()
    50     {
    51         return new NorthVegetable();
    52     }
    53 } 
    54 #南方工厂类
    55 class SouthFactory implements Factory
    56 {
    57     public function createFruit()
    58     {
    59         return new SouthFruit();
    60     }
    61 
    62     public function createVegetable()
    63     {
    64         return new SouthVegetable();
    65     }
    66 } 
    67 
    68 #------------------------------#
    69 #客户端
    70 #想要哪个对象就找工厂
    71 $northFactory=new NorthFactory();
    72 $a=$northFactory->createFruit();    #获取北方水果对象
    73 
    74 ?>

    优点:

    • 封装性
    • 能够快速增加产品等级结构

    缺点:

    • 抽象工厂模式的产品族扩展比较困难

    (以上是自己的一些见解,若有不足或者错误的地方请各位指出)

     作者:那一叶随风   http://www.cnblogs.com/phpstudy2015-6/

     原文地址: https://www.cnblogs.com/phpstudy2015-6/p/6732784.html

     声明:本博客文章为原创,只代表本人在工作学习中某一时间内总结的观点或结论。转载时请在文章页面明显位置给出原文链接

  • 相关阅读:
    沙盒解决方案part1:沙盒解决方案的用途和好处
    session定义使用和丢失问题小结(20120101有更新&&20121026又更)
    普通pc检测维修的一个特例:检测\换板\电源\IDE信道\声卡驱动
    用户sa登录失败,该用户与可信sql server连接无关联
    trycatchfinally(C# 简单学习)
    按钮只能一次提交:ajax页面中调用ascx控件,如何设置ascx中按钮为false
    开始学习:Ajax的全称是:AsynchronousJavaScript+XML
    ajax学习的第一次亲密接触.(虽然还有一点模糊)
    .net2.0 在应用程序级别之外使用注册为 allowDefinition='MachineToApplication' 的节是错误的
    创建可重复使用的控件ascx-一页只能有一个服务器端 Form 标记?
  • 原文地址:https://www.cnblogs.com/phpstudy2015-6/p/6732784.html
Copyright © 2011-2022 走看看