zoukankan      html  css  js  c++  java
  • 《Head First 设计模式》 读书笔记04 工厂模式(一)

    《Head First 设计模式》读书笔记04 工厂模式

     

    问题的提出

      如何将实例化具体类的代码从应用中抽离,或者封装起来,使它们不会干扰应用的其他部分?

      假设你有一个披萨店,那么代码最初可能是这样:

    最初的披萨店代码
    Pizza oderPizza(String type)
    {
        //Pizza是一个接口
        Pizza pizza;
    
        //随着时间改变的地方
        if(type.equals("cheese"))
        {
            pizza = new CheesePizza();
        }
        else if(type.equals("greel"))
        {
            pizza = new GreekPizza();
        }
        else if(type.equals("pepperoni"))
        {
            pizza = new PepperoniPizza();
        }
    
        //不改变的地方
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }

      披萨类型可能随着时间各种改变,那么找到了改变的部分和不变的部分之后,使用封装将创建对象的部分移到外面去。

      封装创建对象的代码

      

     

     

    新的实现——简单工厂

       利用工厂封装后,新的实现代码如下:

      

    简单工厂实现披萨店
    public class SimplePizzaFactory
    {
        public Pizza createPizza(String type)
        {
            Pizza pizza = null;        
            if(type.equals("cheese"))
            {
                pizza = new CheesePizza();
            }
            else if(type.equals("greel"))
            {
                pizza = new GreekPizza();
            }
            else if(type.equals("pepperoni"))
            {
                pizza = new PepperoniPizza();
            }
            return pizza;
        }
    }
    public class PizzaStore
    {
        SimplePizzaFactory factory;
    
        public PizzaStore(SimplePizzaFactory factory)
        {
            this.factory = factory;
        }
        public Pizza orderPizza(String type)
        {
            Pizza pizza;
            pizza = factory.createPizza(type);
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }
    }

     

       类图:

      

     

     

    重要提醒

      在设计模式中,所谓的“实现一个接口”并不一定表示“写一个类,并用implements关键字来实现某个Java接口”。

      “实现一个接口”泛指“实现某个超类型(可以是类或接口)的某个方法”。

     

    有更多不同地区的加盟披萨店

      一种做法:设计出不同的工厂类

      每个地区用自己的工厂类加工披萨,每个地区也有自己的PizzaStore对象,建立对象时将自己的工厂类对象加入。框架不变。

      想要更多的质量控制

      把createPizza()方法放回到PizzaStore中,设置成抽象方法,然后为每个区域风味创建一个PizzaStore的子类。

      这种方法实现起来代码如下:

     

    工厂方法实现披萨店
    public abstract class PizzaStore
    {
    
        public Pizza orderPizza(String type)
        {
            Pizza pizza;
            pizza = createPizza(type);
    
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
    
            return pizza;
        }
        protected abstract Pizza createPizza(String type);
    }

    工厂方法

      上面的例子中,实例化披萨的责任被移到一个方法中,这个方法就如同是一个“工厂”。

      工厂方法用来处理对象的创建,并将这样的行为封装在子类中。

      这样,客户程序中关于超类的代码就和子类对象创建代码解耦了。

      abstract Product factoryMethod(String type);

      工厂方法是抽象的,所以依赖子类来处理对象的创建。

      工厂方法必须返回一个产品。超类中定义的方法,通常使用到工厂方法的返回值。

      工厂方法将客户(也就是超类中的代码,如orderPizza())和实际创建具体产品的代码分隔开来。

      工厂方法可能需要参数(也可能不需要)来指定所需要的产品。

     

    工厂方法模式

      工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。

      工厂方法让类把实例化推迟到子类。

      见类图:

      

     

      ConcreteCreator可以有一个或多个,选择了子类,则选择了实际创建的工厂方法。

      这个具体的工厂可以只创建一种对象,也可以根据传入的参数创建不同的对象。

      工厂方法和Creator并不总是抽象的,也可以提供默认的具体实现。

     

    设计原则——依赖倒置原则Dependency Inversion Principle

      要依赖抽象,不要依赖具体类。

      不能让高层组件依赖底层组件。

      前面所说的做法就体现了这个设计原则,倒置依赖后:让高层组件PizzaStore依赖于一个抽象的Pizza,而各种具体的披萨也依赖于这个抽象的Pizza。

      几个指导方针帮助你遵循此原则:

      变量不可以持有具体类的引用。

      如果使用new,就会持有具体类的引用,可以使用工厂来避开这样的做法。

      不要让类派生自具体类。

      如果派生自具体类,就会依赖具体类。要派生自抽象类或接口。

      不要覆盖基类中已实现的方法。

      如果覆盖基类已实现的方法,那么基类不是一个真正适合被继承的抽象。基类中已实现的方法应该由所有的子类共享。

      这些原则应尽量达到,而不是随时都要遵循,有时候有足够的理由,就可以违反这些方针。(Orz)。

  • 相关阅读:
    __iter__方法demo
    开放封闭原则
    单例模式
    Python赋值、浅拷贝、深拷贝
    保留原页面的参数条件
    request.GET、request.POST、request.body(持续更新)
    面向对象的封装、继承、多态(持续更新)
    关于Form、ModelForm的一些操作(持续更新)
    创建类的两种方式
    Nginx深度优化
  • 原文地址:https://www.cnblogs.com/mengdd/p/2844868.html
Copyright © 2011-2022 走看看