zoukankan      html  css  js  c++  java
  • 设计模式之工厂模式(一)

    工厂模式的学习篇幅比较长,小编第一次看书的时候,就一口气花了一个多小时,还是通读。后面又断断续续地继续了解了下,力争做到清晰的认知,给大家一个简单的学习方式。所以,这次模块分的可能会比之前的多,涉及到多个工厂模式。好的,我们继续冲鸭!!!

    除了使用new操作符之外,还有更多制造对象的方法。我们将了解到实例化这个活动不应该总是公开地进行,也会认识到初始化经常会造成“耦合”问题。所以,这肯定不是我们希望的这样对吧?继续学习下去,我们将了解工厂模式如何从复杂的依赖中帮你脱困。

    当看到“new”,就会想到“具体”

    很多朋友应该有一个疑惑,之前说的原则,不应该针对实现编程,但是当我们每次使用new的时候,其实就是在针对实现编程呀。使用了“new”,就是在实例化一个具体类,所以用的的确是实现,而不是接口。遇到一个类的情况,还好说,但是遇到多个类,就必须等到运行时,才知道该实例化哪一个。

    Duck duck;
    if(picnic) {
        duck = new MallardDuck();
    } else if (hunting) {
        duck = new DecoyDuck();
    } else if (inBathTub) {
        duck = new RubberDuck();
    }
    

    这段代码如果一旦有变化扩展,就必须重新打开这段代码进行检查和修改,势必会造成部分系统更难维护和更新,也更容易犯错。

    “new”有什么不对劲

    针对Java程序来说,new是最最基础的部分了,所以从技术上来说,new丝毫没有问题,问题的关键在于经常要进行的改变。

    针对接口编程,可以隔离掉以后系统可能发生的一大堆改变。为啥呢?如果代码是针对接口编程,那么通过多态可以与任何新类实现该接口。但是,当代码使用大量的具体类时,这就很麻烦了,就必须对代码进行改变。也就是说,你的代码并非“对修改关闭”。想用新的具体类型来扩展代码,就必须重新 打开它。

    所以,有没有解决办法呢?还记得我们的第一个原则不,就是用来改变,并帮我们“找出会变化的方面,把它们从不变的部分分离出来”。

    之前的装饰者模式,我们喝了可口的咖啡,那么在工厂模式里,就让我们给咖啡加点搭配,来尝尝披萨的口味吧。

    识别变化的方面,以及你的初步判断

    假设你有一个披萨店,为了让系统有弹性,很是希望这是一个抽象类或接口。但如果这样,这些类或接口就无法直接实例化了。

    Pizza orderPizza() {
        Pizza pizza = new Pizza();
        
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza
    }
    

    所以,我们还是需要增加一些代码,来“决定”适合披萨的类型,然后再“制造”披萨:

    public Pizza orderPizza(String type) {
    		Pizza pizza;
    		
    		// 根据披萨的类型,我们实例化正确的具体类,然后将其赋值给pizza实例化变量。
    		// 请注意,这里的任何披萨都必须实现Pizza接口
    		if ("cheese".equals(type)) {
    			pizza = new CheesePizza();
    		} else if ("greek".equals(type)) {
    			pizza = new GreekPizza();
    		} else if ("pepperoni".equals(type)) {
    			pizza = new PepperoniPizza();
    		}
    		
    		// 一旦我们有了披萨,需要做一些必要的工作。每个Pizza的子类型都知道如何准备自己
    		pizza.prepare();
    		pizza.bake();
    		pizza.cut();
    		pizza.box();
    		return pizza;
    	}
    

    但是压力来自增加更多的披萨类型

    但是,每个产业都会存在竞争对手的,是吧。当其他的披萨店开发出了新产品,你怎么办呢。比如人家有了Clam Pizza、Veggie Pizza。还能怎么办,必须与时俱进,与对手一同进步,把这些披萨加入到你的店里,顺带淘汰一些过时了的披萨。

    完蛋了,如果要增加披萨,又要去淘汰过时的披萨,在程序的世界里就是实例化某些类,删除某些实例化的类。orderPizza()出问题了,我们无法让orderPizza()对修改关闭;所以,我们用到了第一节学到的封装,我们要封装这些增删改的东西。

    封装创建对象的代码

    那么封装什么才是符合我们预期的呢,显而易见,现在最好将创建对象移到orderPizza()之外。但怎么做呢?我们要把创建披萨的代码移到另一个对象中,由这个对象专职创建披萨。

    if ("cheese".equals(type)) {
    	pizza = new CheesePizza();
    } else if ("greek".equals(type)) {
    	pizza = new GreekPizza();
    } else if ("pepperoni".equals(type)) {
    	pizza = new PepperoniPizza();
    }
    

    就是把这个移走,新建一个对象,这个新对象只管如何创建披萨。如果任何对象想要创建披萨,直接就找这个即可。

    我们称这个新对象为“工厂”,并建造工厂

    工厂(factory)处理创建对象的细节,一旦有了SimplePizzaFactory,orderPizza()就变成此对象的客户。现在,我们方式很简单了,当你想要一个披萨的时候,你就叫披萨工厂去做一个就好了。orderPizza()方法只关心从工厂得到了一个披萨,而这个披萨实现了Pizza接口,所以他可以调用prepare()、bake()、cut()、box()来分别进行准备、烘烤、切片、盒装。

    那我们把这个工厂建造起来吧,还不赶紧的。

    // 这个工厂只做一件事,帮他的客户创建披萨
    public class SimplePizzaFactory {
    
    	// 在工厂内定义一个方法createPizza()方法,所有客户用这个方法来实例化新对象
    	public Pizza createPizza(String type) {
    		Pizza pizza = null;
    
    		if (type.equals("cheese")) {
    			pizza = new CheesePizza();
    		} else if (type.equals("pepperoni")) {
    			pizza = new PepperoniPizza();
    		} else if (type.equals("clam")) {
    			pizza = new ClamPizza();
    		} else if (type.equals("veggie")) {
    			pizza = new VeggiePizza();
    		}
    		return pizza;
    	}
    }
    

    虽然这个类还是需要进行频繁的增删改的,还是有点麻烦,但是相比之前呢。为什么这么说,因为这个类,还可以有很多行为,这会儿是创建披萨,那也许是创建菜单呢,又或者是创建饿了么外卖呢,都可以在这个工厂类里创建出来,其他类,只需要调用即可。所以,也就是说,当以后有任何改变,只需要修改这个类即可,省去你在其他地方操作的烦恼。

    有了工厂类,其他类的操作就要随之更改了。PizzaStore类需要把这个工厂加进来,毕竟我们什么事情都交给工厂去完成了。修改如下:

    // 你需要更多的披萨类型传入orderPizza()
    	public Pizza orderPizza(String type) {
    		Pizza pizza;
    		pizza = factory.createPizza(type);
    				
    		// 一旦我们有了披萨,需要做一些必要的工作。每个Pizza的子类型都知道如何准备自己
    		pizza.prepare();
    		pizza.bake();
    		pizza.cut();
    		pizza.box();
    		return pizza;
    	}
    

    定义简单工厂

    简单工厂其实不是一个设计模式,反而比较像是一种变成习惯。但由于经常被使用,所以在书中,给他一个“Head First Pattern荣誉奖”。有些开发人员的确是把这个编程习惯误认为是“工厂模式”(Factory Pattern)。但是不要因为简单工厂不是一个设计模式,就忽略了他。让我们来看看新的披萨店的类图:

    好啦,工厂模式的热身结束啦。谢谢简单工厂模式给我们暖身,之后我们会进入两个重量级的模式,他们都是工厂。所以,别担心你吃不到披萨,后面还会有更多的披萨呢。

    再提醒一次,在设计模式中,所谓的“实现一个接口”并“不一定”表示“写一个类,并利用implement关键词来实现某个Java接口”。“实现一个接口”泛指“实现某个超类型(可以使类或接口)的某个方法”。

    简单工厂你get了吗?

    推荐阅读:

    GitHub地址 HeadFirstDesign

    爱生活,爱学习,爱感悟,爱挨踢

  • 相关阅读:
    《Java编程思想》阅读笔记二
    《Java编程思想》阅读笔记一
    【Android开发日记】之入门篇(十五)——ViewPager+自定义无限ViewPager
    将你的代码上传 Bintray 仓库
    Volley框架的流程图分析
    Volley框架的使用
    【Android开发日记】之基础篇(二)——Android的动画效果
    maven项目的多级目录
    【Android开发日记】之基础篇(一)——TextView+SpannableStringBuilder
    Android APP安装后不在桌面显示图标的应用场景举例和实现方法
  • 原文地址:https://www.cnblogs.com/dimple91/p/10716288.html
Copyright © 2011-2022 走看看