设计模式之工厂模式

当我们只用new去创建一个类时,我们就在针对这个具体类编程。如果能够不使用具体类,而是针对接口编程,将会对以后扩展有很大方便。

情景:

你是一个披萨店的老板,披萨有很多种类。

我们可能需要这么做

</span><span style="color: #0000ff;"&gt;if</span> (type == <span style="color: #800000;"&gt;A</span><span style="color: #000000;"&gt;) { pizza </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; APizza(); } </span><span style="color: #0000ff;"&gt;else</span> <span style="color: #0000ff;"&gt;if</span> (type == <span style="color: #800000;"&gt;B</span><span style="color: #000000;"&gt;) { pizza </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; BPizza(); } </span><span style="color: #0000ff;"&gt;else</span> <span style="color: #0000ff;"&gt;if</span> (type == <span style="color: #800000;"&gt;C</span><span style="color: #000000;"&gt;) { pizza </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; CPizza(); } ... </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 制作披萨订单的其他操作</span>

}

但是以后我们可能会有D,E,F....之列的更多的披萨。我们必须重新修改这份代码。

根据“封装变化”的设计原则,我们需要把创建对象的部分封装起来。

= </span><span style="color: #0000ff;"&gt;if</span> (type.equals("A"<span style="color: #000000;"&gt;)) { pizza </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; APizza(); } </span><span style="color: #0000ff;"&gt;else</span> <span style="color: #0000ff;"&gt;if</span> (type.equals("B"<span style="color: #000000;"&gt;)) { pizza </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; BPizza(); } </span><span style="color: #0000ff;"&gt;else</span> <span style="color: #0000ff;"&gt;if</span> (type.equals("C"<span style="color: #000000;"&gt;)) { pizza </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; CPizza(); } </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; pizza; }

}

这样在制作订单时只需在工厂取一个Pizza就可以了。

</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; PizzaStore(SimplePizzaFactory factory) { </span><span style="color: #0000ff;"&gt;this</span>.factory =<span style="color: #000000;"&gt; factory; } </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; Pizza orderPizza(String type) { Pizza pizza; pizza </span>=<span style="color: #000000;"&gt; factory.createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; pizza; }

}

现在有很地区要建立披萨店的分店,你希望所有的店都有相同的流程,但是不同的地区会有不同的口味,比如有些地方只吃DEF口味的披萨,也就是说不同地区要有不同的工厂,没有方法把Pizza的制作活动全部局限于PizzaStore类呢?

方法是把createPizza放进PizzaStore类中,并设置成抽象方法,具体实现由每一个地区的子类完成。

</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; Pizza orderPizza(String type) { Pizza pizza; pizza </span>=<span style="color: #000000;"&gt; createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; pizza; } </span><span style="color: #0000ff;"&gt;abstract</span><span style="color: #000000;"&gt; Pizza createPizza(String type);

}

Product factoryMethod(String type) 

我们最一开始的代码,PizzaStore的实现是依赖于具体Pizza类的,使用工厂模式后,它已经不再依赖于具体的披萨类,也就是减少了对具体类的依赖。

设计原则:依赖倒置原则(Dependency Inverseion Principle)

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

 这个原则说明了,不要让高层组件依赖底层组件,而且,不管高层组件还是底层组件,两者都应该依赖抽象。

使用了工厂方法模式之后,PizzaStore类依赖Pizza这个接口,而具体的APizza,BPizza等具体披萨类也依赖于Pizza这个接口,这就是一种依赖倒置。

………………

现在又有一个新的问题

就是具体Pizza的制作。上面没有写具体披萨的制作过程,默认都是一样的。但是!不同地区用到原料也可能有不同,例如A地产辣椒和B地是不一样的,于是,我们还应该给Pizza写一个原料工厂~~~

首先为工厂定义一个接口

为每一个地区创建一个原料工厂,比如纽约的原料工厂

NYPizzaIngredientFactory @Override </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; Dough createDough() { </span><span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; ThinCrustDough(); } @Override </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; Sauce createSauce() { </span><span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; MarinaraSauce(); } @Override </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; Cheese createCheese() { </span><span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; ReggianoCheese(); } @Override </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; Veggies[] createVeggies() { Veggies[] veggies </span>= { <span style="color: #0000ff;"&gt;new</span> Garlic(),<span style="color: #0000ff;"&gt;new</span> Onion(),<span style="color: #0000ff;"&gt;new</span> Mushroom(),<span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; RedPepper() }; </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; veggies; } @Override </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; Pepperoni createPepperoni() { </span><span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; SlicedPepperni(); } @Override </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; Clams createClam() { </span><span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; FreshClams(); }

}

抽象的Pizza类

String name; Dough dough; Sauce sauce; Veggies veggies[]; Cheese cheese; Pepperoni pepperoni; Clams clams; </span><span style="color: #0000ff;"&gt;abstract</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; prepare(); </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; bake() { System.out.println(</span>"Bake for 25 minutes at 350."<span style="color: #000000;"&gt;); } </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; cut() { System.out.println(</span>"Cutting the pizza into diagonal slices."<span style="color: #000000;"&gt;); } </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; box() { System.out.println(</span>"Place pizza in official PizzaStore box."<span style="color: #000000;"&gt;); } </span><span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; setName(String name) { </span><span style="color: #0000ff;"&gt;this</span>.name =<span style="color: #000000;"&gt; name; } String getName() { </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; name; } </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; String toString() { </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; name; }

}

具体的Pizza类。每个Pizza的制作流程其实是一样的。只有原料不同,同时原料会和地点有关。为具体的类添加一个原料工厂。

CheesePizza PizzaIngredientFactory ingredientFactory; </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; CheesePizza(PizzaIngredientFactory ingredientFactory) { </span><span style="color: #0000ff;"&gt;this</span>.ingredientFactory =<span style="color: #000000;"&gt; ingredientFactory; } @Override </span><span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; prepare() { System.out.println(</span>"Preparing " +<span style="color: #000000;"&gt; name); dough </span>=<span style="color: #000000;"&gt; ingredientFactory.createDough(); sauce </span>=<span style="color: #000000;"&gt; ingredientFactory.createSauce(); cheese </span>=<span style="color: #000000;"&gt; ingredientFactory.createCheese(); }

}

纽约的PizzaStore类

NYPizzaStore @Override Pizza createPizza(String item) { Pizza pizza </span>= <span style="color: #0000ff;"&gt;null</span><span style="color: #000000;"&gt;; PizzaIngredientFactory ingredientFactory </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; NYPizzaIngredientFactory(); </span><span style="color: #0000ff;"&gt;if</span> (item.equals("cheess"<span style="color: #000000;"&gt;)) { pizza </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; ChessPizza(ingredientFactory); } </span><span style="color: #0000ff;"&gt;else</span> <span style="color: #0000ff;"&gt;if</span> (item.equals("veggie"<span style="color: #000000;"&gt;)) { pizza </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; VeggiePizza(); pizza.setName(</span>"New York Style Veggie Pizza."<span style="color: #000000;"&gt;); } </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; else if .... 还有其他种类的Pizza </span> <span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; pizza; }

}

完成~~

我们引入了新类型的工厂,也就是所谓的抽象工厂,来创建披萨家族。

抽象工程模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

抽象工厂允许客户使用抽象类的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。这样一来,客户就从具体产品中被解耦。

类图

工厂方法模式通过继承,而抽象工厂模式是通过组合实现。

抽象工厂是用来创建一个产品家族的抽象类型,可以把一群相关产品集合起来。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结