工厂与抽象工厂 -ag凯发k8国际
本篇文章代码:https://gitee.com/bithachi_admin_admin/mycode/tree/master/设计模式/factory
1. 什么是工厂模式?
- 工厂模式(factory pattern)提供了一种创建对象的最佳方式,是 java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式。
- 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
**意图:**定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。(依赖倒置原则)
**主要解决:**主要解决接口选择的问题。
**何时使用:**我们明确地计划不同条件下创建不同实例时。
**如何解决:**让其子类实现工厂接口,返回的也是一个抽象的产品。
**关键代码:**创建过程在其子类执行。
应用实例:
- 您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。
- mybatis换数据库只需换方言和驱动就可以。
优点:
- 一个调用者想创建一个对象,只要知道其名称就可以了。
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
- 屏蔽产品的具体实现,调用者只关心产品的接口。
**缺点:**每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
使用场景:
- 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
- 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
- 设计一个连接服务器的框架,需要三个协议,“pop3”、“imap”、“http”,可以把这三个作为产品类,共同实现一个接口。
**注意事项:**作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
2. 加盟披萨店案例
案例描述:你有一家披萨店,经营有成,击败了许多的竞争者,现在你想开扩大市场,建立加盟店。因为区域的差异,每家加盟店都可能想要提供不同风味的比萨(比方说纽约、芝加哥、加州),这受到了开店地点及该地区比萨美食家口味的影响。那么如何设计呢?
下面是案例的uml模型设计图:
pizzastore:
public abstract class pizzastore {abstract pizza createpizza(string item);public pizza orderpizza(string type) {pizza pizza = createpizza(type);system.out.println("--- making a " pizza.getname() " ---");pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;} }nypizzastore:
public class nypizzastore extends pizzastore {@overridepizza createpizza(string item) {if (item.equals("cheese")) {return new nystylecheesepizza();} else if (item.equals("veggie")) {return new nystyleveggiepizza();} else if (item.equals("clam")) {return new nystyleclampizza();} else if (item.equals("pepperoni")) {return new nystylepepperonipizza();} else {return null;}} }pizza:
import java.util.arraylist; public abstract class pizza {string name;string dough;string sauce;arraylist<string> toppings = new arraylist<string>();void prepare() {system.out.println("prepare " name);system.out.println("tossing dough...");system.out.println("adding sauce...");system.out.println("adding toppings: ");for (string topping : toppings) {system.out.println(" " topping);}}void bake() {system.out.println("bake for 25 minutes at 350");}void cut() {system.out.println("cut the pizza into diagonal slices");}void box() {system.out.println("place pizza in official pizzastore box");}public string getname() {return name;}@overridepublic string tostring() {stringbuffer display = new stringbuffer();display.append("---- " name " ----\n");display.append(dough "\n");display.append(sauce "\n");for (string topping : toppings) {display.append(topping "\n");}return display.tostring();} }nystylecheesepizza**:**
public class nystylecheesepizza extends pizza {public nystylecheesepizza() { name = "ny style sauce and cheese pizza";dough = "thin crust dough";sauce = "marinara sauce";toppings.add("grated reggiano cheese");} }披萨店测试:
public class pizzatestdrive {public static void main(string[] args) {pizzastore nystore = new nypizzastore();pizzastore chicagostore = new chicagopizzastore();pizza pizza = nystore.orderpizza("cheese");system.out.println("ethan ordered a " pizza.getname() "\n");pizza = chicagostore.orderpizza("cheese");system.out.println("joel ordered a " pizza.getname() "\n");pizza = nystore.orderpizza("clam");system.out.println("ethan ordered a " pizza.getname() "\n");pizza = chicagostore.orderpizza("clam");system.out.println("joel ordered a " pizza.getname() "\n");pizza = nystore.orderpizza("pepperoni");system.out.println("ethan ordered a " pizza.getname() "\n");pizza = chicagostore.orderpizza("pepperoni");system.out.println("joel ordered a " pizza.getname() "\n");pizza = nystore.orderpizza("veggie");system.out.println("ethan ordered a " pizza.getname() "\n");pizza = chicagostore.orderpizza("veggie");system.out.println("joel ordered a " pizza.getname() "\n");} }运行结果:
--- making a ny style sauce and cheese pizza --- prepare ny style sauce and cheese pizza tossing dough... adding sauce... adding toppings: grated reggiano cheese bake for 25 minutes at 350 cut the pizza into diagonal slices place pizza in official pizzastore box ethan ordered a ny style sauce and cheese pizza--- making a chicago style deep dish cheese pizza --- prepare chicago style deep dish cheese pizza tossing dough... adding sauce... adding toppings: shredded mozzarella cheese bake for 25 minutes at 350 cutting the pizza into square slices place pizza in official pizzastore box joel ordered a chicago style deep dish cheese pizza--- making a ny style clam pizza --- prepare ny style clam pizza tossing dough... adding sauce... adding toppings: grated reggiano cheesefresh clams from long island sound bake for 25 minutes at 350 cut the pizza into diagonal slices place pizza in official pizzastore box ethan ordered a ny style clam pizza--- making a chicago style clam pizza --- prepare chicago style clam pizza tossing dough... adding sauce... adding toppings: shredded mozzarella cheesefrozen clams from chesapeake bay bake for 25 minutes at 350 cutting the pizza into square slices place pizza in official pizzastore box joel ordered a chicago style clam pizza--- making a ny style pepperoni pizza --- prepare ny style pepperoni pizza tossing dough... adding sauce... adding toppings: grated reggiano cheesesliced pepperonigarliconionmushroomsred pepper bake for 25 minutes at 350 cut the pizza into diagonal slices place pizza in official pizzastore box ethan ordered a ny style pepperoni pizza--- making a chicago style pepperoni pizza --- prepare chicago style pepperoni pizza tossing dough... adding sauce... adding toppings: shredded mozzarella cheeseblack olivesspinacheggplantsliced pepperoni bake for 25 minutes at 350 cutting the pizza into square slices place pizza in official pizzastore box joel ordered a chicago style pepperoni pizza--- making a ny style veggie pizza --- prepare ny style veggie pizza tossing dough... adding sauce... adding toppings: grated reggiano cheesegarliconionmushroomsred pepper bake for 25 minutes at 350 cut the pizza into diagonal slices place pizza in official pizzastore box ethan ordered a ny style veggie pizza--- making a chicago deep dish veggie pizza --- prepare chicago deep dish veggie pizza tossing dough... adding sauce... adding toppings: shredded mozzarella cheeseblack olivesspinacheggplant bake for 25 minutes at 350 cutting the pizza into square slices place pizza in official pizzastore box joel ordered a chicago deep dish veggie pizza进程已结束,退出代码01. 什么是抽象工厂模式?
- 抽象工厂模式(abstract factory pattern)是围绕一个超级工厂创建其他工厂。该超级工厂为其他工厂的父工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
- 在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
**意图:**提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
**主要解决:**主要解决接口选择的问题。
**何时使用:**系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
**如何解决:**在一个产品族里面,定义多个产品。
**关键代码:**在一个工厂里聚合多个同类产品。
**应用实例:**工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况,在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 oop 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。
**优点:**当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
**缺点:**产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 creator 里加代码,又要在具体的里面加代码。
使用场景: 1、qq 换皮肤,一整套一起换。 2、生成不同操作系统的程序。
**注意事项:**产品族难扩展,产品等级易扩展。
2. 给加盟披萨店新增原料工厂
案例描述:你有一家披萨店,经营有成,击败了许多的竞争者,现在你想开扩大市场,建立加盟店。因为区域的差异,每家加盟店都可能想要提供不同风味的比萨(比方说纽约、芝加哥、加州),这受到了开店地点及该地区比萨美食家口味的影响。那么如何设计呢?这是我们工厂模式的案例,现在我们在此案例上加点东西,我们希望所有的加盟店都使用统一的调料(原料):面团、酱料、腊肠、芝士、蔬菜、肉等。我们可以建造原料工厂来满足这种需求。
下面是uml设计模型:
下面给出核心实现代码;
**
**
披萨抽象类pizza:
public abstract class pizza {string name;dough dough;sauce sauce;veggies veggies[];cheese cheese;pepperoni pepperoni;clams clam;abstract void prepare();void bake() {system.out.println("bake for 25 minutes at 350");}void cut() {system.out.println("cutting the pizza into diagonal slices");}void box() {system.out.println("place pizza in official pizzastore box");}void setname(string name) {this.name = name;}string getname() {return name;}@overridepublic string tostring() {stringbuffer result = new stringbuffer();result.append("---- " name " ----\n");if (dough != null) {result.append(dough);result.append("\n");}if (sauce != null) {result.append(sauce);result.append("\n");}if (cheese != null) {result.append(cheese);result.append("\n");}if (veggies != null) {for (int i = 0; i < veggies.length; i) {result.append(veggies[i]);if (i < veggies.length-1) {result.append(", ");}}result.append("\n");}if (clam != null) {result.append(clam);result.append("\n");}if (pepperoni != null) {result.append(pepperoni);result.append("\n");}return result.tostring();} }具体的某种披萨类cheesepizza:
public class cheesepizza extends pizza {//原料工厂pizzaingredientfactory ingredientfactory;public cheesepizza(pizzaingredientfactory ingredientfactory) {this.ingredientfactory = ingredientfactory;}@overridevoid prepare() {system.out.println("preparing " name);dough = ingredientfactory.createdough();sauce = ingredientfactory.createsauce();cheese = ingredientfactory.createcheese();} }披萨店抽象类pizzastore:
public abstract class pizzastore {protected abstract pizza createpizza(string item);public pizza orderpizza(string type) {pizza pizza = createpizza(type);system.out.println("--- making a " pizza.getname() " ---");pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;} }纽约披萨店nypizzastore:
**
**
原料工厂抽象类****pizzaingredientfactory:
public interface pizzaingredientfactory {public dough createdough();public sauce createsauce();public cheese createcheese();public veggies[] createveggies();public pepperoni createpepperoni();public clams createclam(); }具体的纽约原料工厂****nypizzaingredientfactory:
public class nypizzaingredientfactory implements pizzaingredientfactory {@overridepublic dough createdough() {return new thincrustdough();}@overridepublic sauce createsauce() {return new marinarasauce();}@overridepublic cheese createcheese() {return new reggianocheese();}@overridepublic veggies[] createveggies() {veggies veggies[] = { new garlic(), new onion(), new mushroom(), new redpepper() };return veggies;}@overridepublic pepperoni createpepperoni() {return new slicedpepperoni();}@overridepublic clams createclam() {return new freshclams();} }某类型的具体原料产品****mushroom:
public class mushroom implements veggies {@overridepublic string tostring() {return "mushrooms";} }测试运行pizzatestdrive:
public class pizzatestdrive {public static void main(string[] args) {pizzastore nystore = new nypizzastore();pizzastore chicagostore = new chicagopizzastore();pizza pizza = nystore.orderpizza("cheese");system.out.println("ethan ordered a " pizza "\n");pizza = chicagostore.orderpizza("cheese");system.out.println("joel ordered a " pizza "\n");pizza = nystore.orderpizza("clam");system.out.println("ethan ordered a " pizza "\n");pizza = chicagostore.orderpizza("clam");system.out.println("joel ordered a " pizza "\n");pizza = nystore.orderpizza("pepperoni");system.out.println("ethan ordered a " pizza "\n");pizza = chicagostore.orderpizza("pepperoni");system.out.println("joel ordered a " pizza "\n");pizza = nystore.orderpizza("veggie");system.out.println("ethan ordered a " pizza "\n");pizza = chicagostore.orderpizza("veggie");system.out.println("joel ordered a " pizza "\n");} }运行结果:
--- making a new york style cheese pizza --- preparing new york style cheese pizza bake for 25 minutes at 350 cutting the pizza into diagonal slices place pizza in official pizzastore box ethan ordered a ---- new york style cheese pizza ---- thin crust dough marinara sauce reggiano cheese--- making a chicago style cheese pizza --- preparing chicago style cheese pizza bake for 25 minutes at 350 cutting the pizza into diagonal slices place pizza in official pizzastore box joel ordered a ---- chicago style cheese pizza ---- thickcrust style extra thick crust dough tomato sauce with plum tomatoes shredded mozzarella--- making a new york style clam pizza --- preparing new york style clam pizza bake for 25 minutes at 350 cutting the pizza into diagonal slices place pizza in official pizzastore box ethan ordered a ---- new york style clam pizza ---- thin crust dough marinara sauce reggiano cheese fresh clams from long island sound--- making a chicago style clam pizza --- preparing chicago style clam pizza bake for 25 minutes at 350 cutting the pizza into diagonal slices place pizza in official pizzastore box joel ordered a ---- chicago style clam pizza ---- thickcrust style extra thick crust dough tomato sauce with plum tomatoes shredded mozzarella frozen clams from chesapeake bay--- making a new york style pepperoni pizza --- preparing new york style pepperoni pizza bake for 25 minutes at 350 cutting the pizza into diagonal slices place pizza in official pizzastore box ethan ordered a ---- new york style pepperoni pizza ---- thin crust dough marinara sauce reggiano cheese garlic, onion, mushrooms, red pepper sliced pepperoni--- making a chicago style pepperoni pizza --- preparing chicago style pepperoni pizza bake for 25 minutes at 350 cutting the pizza into diagonal slices place pizza in official pizzastore box joel ordered a ---- chicago style pepperoni pizza ---- thickcrust style extra thick crust dough tomato sauce with plum tomatoes shredded mozzarella black olives, spinach, eggplant sliced pepperoni--- making a new york style veggie pizza --- preparing new york style veggie pizza bake for 25 minutes at 350 cutting the pizza into diagonal slices place pizza in official pizzastore box ethan ordered a ---- new york style veggie pizza ---- thin crust dough marinara sauce reggiano cheese garlic, onion, mushrooms, red pepper--- making a chicago style veggie pizza --- preparing chicago style veggie pizza bake for 25 minutes at 350 cutting the pizza into diagonal slices place pizza in official pizzastore box joel ordered a ---- chicago style veggie pizza ---- thickcrust style extra thick crust dough tomato sauce with plum tomatoes shredded mozzarella black olives, spinach, eggplant进程已结束,退出代码0- 工厂方法使用继承: 把对象的创建委托给子类,子类实现工厂方法来创建对象。
- 抽象工厂使用对象组合(在): 对象的创建被实现在工厂接口所暴露出来的方法中。