zoukankan      html  css  js  c++  java
  • Head First 设计模式 --4 工厂模式 抽象工厂模式

    (用到了依赖倒置原则)

    我们写的代码中,有的时候可能会出现根据外面给定的不同的参数在方法中根据参数实例化不同的实例,就是会根据不同的参数会new出不同的实例。如果这么写了,这段代码会非常的脆弱,一旦出现新的类型,那么就需要重写将这段代码找出来添加写的new。
    之前说过针对接口编程,而不是针对实现。这句话也可以理解成,代码中尽量不要出现具体的实例。能用到实例的地方,应该用超类来代替,通过多态让代码走正确的分支。

    通过例子来说明(看的就是《Head First 设计模式》这本书,所有还是用书中的例子)
    不用工厂模式,我们就是这么写

    Pizza orderPizza(String type){
        Pizaa pizza;
        if (type.equals("cheese")) {
            pizza = new CheesePizza();
        } else if (type.equals("clam")) {
            pizza = new ClamPizza();
        }
    
        pizza.prepare();
        pizza.bake();
        //.........
    }

    通过工厂模式

      Pizza orderPizza(String type) {
        Pizza pizza = factory.createPizze("cheese");
    
        pizza.prepare();
        pizza.bake();
        // .........
    
        return pizza;
      }
    
    class SimplePizzaFactory {
      public Pizza createPizze(String type) {
        Pizza pizza = null;
        if (type.equals("cheese")) {
          pizza = new CheesePizza();
        } else if (type.equals("clam")) {
          pizza = new ClamPizza();
        }
        return pizza;
      }
    }

    这么一看,我们似乎什么也没干,只是将代码搬到了另外一个地方。但是注意到,修改后的方法中,没有new,以后如果有新的类型的Pizza只需要修改这段代码就可以了,orderPizza的方法不用动。工厂模式就这么简单。还有另外一种类型的工厂模式,用静态方法返回实例对象,这种叫静态工厂。

    class SimplePizzaFactory {
      public static Pizza createCheesePizze() {
        return new CheesePizza();
      }
    
      public static Pizza createClamPizze() {
        return new ClamPizza();
      }
    }

    这就是工厂模式。其实工厂模式像是一种编程习惯。然后说一下抽象工厂模式。

    抽象工厂模式的作用是建立一个产品家族的抽象类型,这个类型的子类定义了实例化实例的方法,想要获取实例,首先要实例这个类型的实例,在将这个实例传入某个工厂中。抽象工厂一般配合着工厂模式使用。抽象工厂的具体工厂通常用工厂方法创建。工厂模式的主要作用是创建类的实例,抽象工厂的作用是创建一系列的实例。

    根据上面修改看一下抽象工厂的代码

    interface Pizza {
      public void prepare();
    
      public void bake();
    }
    
    class NSCheesePizza implements Pizza {
      @Override
      public void prepare() {}
    
      @Override
      public void bake() {}
    }
    
    class NSClamPizza implements Pizza {
      @Override
      public void prepare() {}
    
      @Override
      public void bake() {}
    }
    
    class ChicagoCheesePizza implements Pizza {
      @Override
      public void prepare() {}
    
      @Override
      public void bake() {}
    }
    
    class ChicagoClamPizza implements Pizza {
      @Override
      public void prepare() {}
    
      @Override
      public void bake() {}
    }
    
    abstract class PizzaStore {
    
      public Pizza orderPizza(String type) {
        Pizza pizza = null;
        pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        return pizza;
      }
    
      abstract Pizza createPizza(String type);
    }
    
    class NYPizzaStore extends PizzaStore {
      @Override
      Pizza createPizza(String type) {
        if (type.equals("chesse")) {
          return new NSCheesePizza();
        }
    
        return null;
      }
    }
    
    class ChicagoPizzaStore extends PizzaStore {
      @Override
      Pizza createPizza(String type) {
        if (type.equals("chesse")) {
          return new ChicagoCheesePizza();
        }
    
        return null;
      }
    }
    public class Test {
      public static void main(String[] args) {
        PizzaStore nyStore = new NYPizzaStore();
        Pizza pizza = nyStore.orderPizza("cheese");
      }
    }

    这里用到了依赖倒置原则。怎么倒置的,开始时需要制作不同的pizza,不同的具体类,这样所有的pizza店都会依赖这些具体类。于是,抽象出来了一个Pizza,这样就需要一个pizza工厂,然后所有的pizza类都依赖这样一个抽象,并且pizza店也需要这个抽象。这样我们就倒置了商店依赖具体pizza类的设计。

    怎么才能避免违反依赖倒置原则:
    1、变量不可以持有具体类的引用。(避免使用new)
    2、不要让类派生具体类。
    3、不要覆盖基类已经实现的方法。(如果覆盖了基类的方法,就说明这个类不是一个真正适合的抽象类)

  • 相关阅读:
    [置顶] location.href你真的会用了?
    Hive HA使用说明
    十进制转换为任意进制及操作符重载
    《重构》学习总结
    linux kill进程和子进程小trick
    express for node 路由route几种实现方式的思考
    BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第2章节--SharePoint 2013 App 模型概览 总结
    Can rename table but can not truncate table
    HBase
    链表解说和基本操作练习附代码
  • 原文地址:https://www.cnblogs.com/badboyf/p/6212464.html
Copyright © 2011-2022 走看看