申请书范文网,分享全网优秀范文,学习好帮手!
申请书范文网 > 23种设计模式之简单工厂模式 工厂方法模式 抽象工厂模式详解

23种设计模式之简单工厂模式 工厂方法模式 抽象工厂模式详解

时间:2022-02-08 09:17:40

相关推荐

23种设计模式之简单工厂模式 工厂方法模式 抽象工厂模式详解

工厂模式详解

1. 简单工厂模式1.1 需求分析1.2 使用传统方式实现1.2.1 类图1.2.2 代码实现1.2.2.1 新建pizza抽象类1.2.2.2 希腊披萨实现类1.2.2.3 奶酪披萨实现类1.2.2.4 订购披萨类1.2.2.5 披萨商店类1.2.2.5 运行结果1.2.3 传统方式优缺点分析1.3 改进思路1.4 什么是简单工厂模式1.4.1 新建一个简单工厂类,用于生成pizza1.4.2 修改订购披萨类1.4.3 修改披萨商店类1.5 简单工厂又叫静态工厂2. 工厂方法模式2.1 需求分析2.1.1 思路1:使用简单工厂模式2.1.2 思路2:使用工厂方法模式2.2 什么是工厂方法模式?2.2.1 工厂方法模式设计方案2.3 代码实现2.3.1 类图2.3.2 上代码2.3.2.1 披萨类2.3.2.2 四个实现类2.3.2.3 订购披萨父类2.3.2.3 两个实现类2.3.2.4 披萨商店类,主类2.3.2.5 运行结果3. 抽象工厂模式3.1 什么是抽象工厂模式3.2 类图3.3 代码实现3.3.1 披萨类3.3.2 4个实现类3.3.3 抽象工厂接口3.3.4 两个重新工厂的实现类3.3.5 订购披萨类3.3.6 披萨商店类3.3.7 运行结果4. 工厂模式JDK里的使用5. 工厂模式小结

1. 简单工厂模式

1.1 需求分析

看一个披萨的项目:要便于披萨种类的扩展,要便于维护。

披萨的种类很多,比如GreekPizz,CheesePizz等披萨的制作工序有prepare,bake,cut,box完成披萨店订购功能

1.2 使用传统方式实现

1.2.1 类图

1.2.2 代码实现

1.2.2.1 新建pizza抽象类

package factory.simplefactory.pizzastore.pizza;/*** @author LongXi* @create -07-31 8:47*///将Pizza做成抽象类public abstract class Pizza {//名字protected String name;//准备原材料,不同的披萨不一样,因此我们做成抽象方法public abstract void prepare();//烘烤public void bake(){System.out.println(name + " baking;");}public void cut(){System.out.println(name + " cutting;");}public void box(){System.out.println(name + " boxing;");}public void setName(String name){this.name = name;}}

1.2.2.2 希腊披萨实现类

package factory.simplefactory.pizzastore.pizza;/*** @author LongXi* @create -07-31 8:52*/public class GreekPizza extends Pizza{@Overridepublic void prepare() {System.out.println("给制作希腊披萨,准备原材料");}}

1.2.2.3 奶酪披萨实现类

package factory.simplefactory.pizzastore.pizza;/*** @author LongXi* @create -07-31 8:52*/public class CheesePizza extends Pizza{@Overridepublic void prepare() {System.out.println("给制作奶酪披萨,准备原材料");}}

1.2.2.4 订购披萨类

package factory.simplefactory.pizzastore.order;import factory.simplefactory.pizzastore.pizza.CheesePizza;import factory.simplefactory.pizzastore.pizza.GreekPizza;import factory.simplefactory.pizzastore.pizza.Pizza;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;/*** @author LongXi* @create -07-31 8:55*/public class OrderPizza {public OrderPizza() {Pizza pizza = null;String orderType;//订购披萨类型do {orderType = getType();if (orderType.equals("greek")){pizza = new GreekPizza();pizza.setName("希腊披萨");}else if(orderType.equals("cheese")){pizza = new CheesePizza();pizza.setName("奶酪披萨");} else {break;}//输出披萨制作过程pizza.prepare();pizza.bake();pizza.cut();pizza.box();}while(true);}//加一个方法,可以获取客户希望订购的披萨种类private String getType(){try {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));System.out.println("请输入要订购的pizza种类:");String str = null;str = br.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}}

1.2.2.5 披萨商店类

package factory.simplefactory.pizzastore.order;/*** @author LongXi* @create -07-31 9:08*/public class pizzaStore {public static void main(String[] args) {new OrderPizza();}}

1.2.2.5 运行结果

请输入要订购的pizza种类:greek给制作希腊披萨,准备原材料希腊披萨 baking;希腊披萨 cutting;希腊披萨 boxing;请输入要订购的pizza种类:cheese给制作奶酪披萨,准备原材料奶酪披萨 baking;奶酪披萨 cutting;奶酪披萨 boxing;请输入要订购的pizza种类:lolProcess finished with exit code 0

1.2.3 传统方式优缺点分析

优点:比较好理解,简单易操作缺点:违反了设计模式的OCP原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码。

假如我们现在增加一个新的种类披萨:胡椒披萨

胡椒披萨实现类

package factory.simplefactory.pizzastore.pizza;/*** @author LongXi* @create -07-31 12:11*/public class PepperPizza extends Pizza{@Overridepublic void prepare() {System.out.println("给制作胡椒披萨,准备原材料");}}

订购披萨类也需要响应的更改,加入胡椒披萨判断分支

public OrderPizza() {Pizza pizza = null;String orderType;//订购披萨类型do {orderType = getType();if (orderType.equals("greek")){pizza = new GreekPizza();pizza.setName("希腊披萨");}else if(orderType.equals("cheese")){pizza = new CheesePizza();pizza.setName("奶酪披萨");} else if(orderType.equals("pepper")){pizza = new PepperPizza();pizza.setName("胡椒披萨");break;}//输出披萨制作过程pizza.prepare();pizza.bake();pizza.cut();pizza.box();}while(true);}

执行结果

请输入要订购的pizza种类:pepper给制作胡椒披萨,准备原材料胡椒披萨 baking;胡椒披萨 cutting;胡椒披萨 boxing;请输入要订购的pizza种类:

1.3 改进思路

分析:修改代码可以接受,但是如果我们在其他的地方也有创建Pizza的代码,就意味着,也需要修改,而创建Pizza的代码,往往有多处。

思路:把创建Pizza对象封装到一个类张,这样我们有新的Pizza种类是,只需要修改该类就可,其他有创建到Pizza对象的代码就不需要修改了,这就是简单工厂模式。

1.4 什么是简单工厂模式

简单工厂模式是属于创建型模式,是工厂模式的一种。**简单工厂模式是又一个工厂对象决定创建出哪一种产品类的实例。**简单工厂模式是工厂模式家族中最简单实用的模式。简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)在软件开发中,当我们会用到大量的创建某种,某类或者某批对象时,就会使用到工厂模式。

类图:

1.4.1 新建一个简单工厂类,用于生成pizza

package factory.simplefactory.pizzastore.order;import factory.simplefactory.pizzastore.pizza.CheesePizza;import factory.simplefactory.pizzastore.pizza.GreekPizza;import factory.simplefactory.pizzastore.pizza.PepperPizza;import factory.simplefactory.pizzastore.pizza.Pizza;/*** @author LongXi* @create -07-31 12:29*///简单工厂模式public class SimpleFactory {//根据OrderType返回Pizza对象public Pizza createPizza(String orderType){Pizza pizza = null;System.out.println("使用简单工厂模式");if (orderType.equals("greek")){pizza = new GreekPizza();pizza.setName("希腊披萨");}else if(orderType.equals("cheese")){pizza = new CheesePizza();pizza.setName("奶酪披萨");} else if(orderType.equals("pepper")){pizza = new PepperPizza();pizza.setName("胡椒披萨");}return pizza;}}

1.4.2 修改订购披萨类

package factory.simplefactory.pizzastore.order;import factory.simplefactory.pizzastore.pizza.Pizza;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;/*** @author LongXi* @create -07-31 8:55*/public class OrderPizza {/* public OrderPizza() {Pizza pizza = null;String orderType;//订购披萨类型do {orderType = getType();if (orderType.equals("greek")){pizza = new GreekPizza();pizza.setName("希腊披萨");}else if(orderType.equals("cheese")){pizza = new CheesePizza();pizza.setName("奶酪披萨");} else if(orderType.equals("pepper")){pizza = new PepperPizza();pizza.setName("胡椒披萨");} else {break;}//输出披萨制作过程pizza.prepare();pizza.bake();pizza.cut();pizza.box();}while(true);}*/public OrderPizza (SimpleFactory factory){this.setSimpleFactory(factory);}//定义一个简单工厂对象SimpleFactory simpleFactory;Pizza pizza = null;public void setSimpleFactory(SimpleFactory simpleFactory) {this.simpleFactory = simpleFactory;do {pizza = this.simpleFactory.createPizza(this.getType());if (pizza != null){pizza.prepare();pizza.bake();pizza.cut();pizza.box();} else {System.out.println("对不起,没有该种类的披萨,订购披萨失败");break;}}while(true);}//加一个方法,可以获取客户希望订购的披萨种类private String getType(){try {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));System.out.println("请输入要订购的pizza种类:");String str = null;str = br.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}}

1.4.3 修改披萨商店类

package factory.simplefactory.pizzastore.order;/*** @author LongXi* @create -07-31 9:08*/public class pizzaStore {public static void main(String[] args) {//new OrderPizza();new OrderPizza(new SimpleFactory());System.out.println("退出程序");}}

这样我们就完成了改进,如果再追加一种披萨,我们只需要更改简单工厂类就可以了,而不用去更改订购披萨的类。

1.5 简单工厂又叫静态工厂

2. 工厂方法模式

2.1 需求分析

披萨项目的新需求:客户在点披萨时,可以点不同口味的披萨,比如:北京的奶酪披萨,北京的胡椒披萨或者是伦敦的奶酪披萨,伦敦的胡椒披萨。

2.1.1 思路1:使用简单工厂模式

创建不用的简单工厂类,比如BJPizzaSimpleFactory, LDPizzaSimpleFactory等等,从当前这个案例来说,也是可以的。

但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好。

2.1.2 思路2:使用工厂方法模式

2.2 什么是工厂方法模式?

定义了一个创建对象的抽象方法,由子类决定要实例化的类。

工厂方法模式的核心思想是:将对象的实例化推迟到子类。

2.2.1 工厂方法模式设计方案

将披萨项目的实例化功能抽象成抽象方法,在不同口类点餐子类中具体实现。

2.3 代码实现

2.3.1 类图

2.3.2 上代码

2.3.2.1 披萨类

package factory.factoryMethod.pizzastore.pizza;/*** @author LongXi* @create -07-31 8:47*///将Pizza做成抽象类public abstract class Pizza {//名字protected String name;//准备原材料,不同的披萨不一样,因此我们做成抽象方法public abstract void prepare();//烘烤public void bake(){System.out.println(name + " baking;");}public void cut(){System.out.println(name + " cutting;");}public void box(){System.out.println(name + " boxing;");}public void setName(String name){this.name = name;}}

2.3.2.2 四个实现类

/*** @author LongXi* @create -07-31 13:15*/public class BJCheesePizza extends Pizza{@Overridepublic void prepare() {setName("北京奶酪披萨");System.out.println("北京奶酪披萨 准备原材料");}}

/*** @author LongXi* @create -07-31 13:15*/public class BJPepperPizza extends Pizza{@Overridepublic void prepare() {setName("北京胡椒披萨");System.out.println("北京胡椒披萨 准备原材料");}}

/*** @author LongXi* @create -07-31 13:15*/public class LDCheesePizza extends Pizza{@Overridepublic void prepare() {setName("伦敦奶酪披萨");System.out.println("伦敦奶酪披萨 准备原材料");}}

/*** @author LongXi* @create -07-31 13:15*/public class LDPepperPizza extends Pizza{@Overridepublic void prepare() {setName("伦敦胡椒披萨");System.out.println("伦敦胡椒披萨 准备原材料");}}

2.3.2.3 订购披萨父类

package factory.factoryMethod.pizzastore.order;import factory.factoryMethod.pizzastore.pizza.Pizza;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;/*** @author LongXi* @create -07-31 8:55*/public abstract class OrderPizza {//定义一个抽象方法,cteatePizzaabstract Pizza cteatePizza (String orderType);public OrderPizza() {Pizza pizza = null;String orderType = null;//订购披萨类型do {orderType = getType();//抽象方法,由工厂子类完成pizza = this.cteatePizza(orderType);//输出披萨制作过程pizza.prepare();pizza.bake();pizza.cut();pizza.box();}while(true);}//加一个方法,可以获取客户希望订购的披萨种类private String getType(){try {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));System.out.println("请输入要订购的pizza种类:");String str = null;str = br.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}}

2.3.2.3 两个实现类

/*** @author LongXi* @create -07-31 13:27*/public class BJOrderPizza extends OrderPizza{@OverridePizza cteatePizza(String orderType) {Pizza pizza = null;if (orderType.equals("cheese")){pizza = new BJCheesePizza();} else if (orderType.equals("pepper")){pizza = new BJPepperPizza();}return pizza;}}

/*** @author LongXi* @create -07-31 13:27*/public class LDOrderPizza extends OrderPizza{@OverridePizza cteatePizza(String orderType) {Pizza pizza = null;if (orderType.equals("cheese")){pizza = new LDCheesePizza();} else if (orderType.equals("pepper")){pizza = new LDPepperPizza();}return pizza;}}

2.3.2.4 披萨商店类,主类

/*** @author LongXi* @create -07-31 13:32*/public class PizzaStore {public static void main(String[] args) {String local = "BJ";if (local.equals("BJ")){// 创建北京口味的各种pizzanew BJOrderPizza();}else {//创建伦敦口味的各种pizzanew LDOrderPizza();}}}

2.3.2.5 运行结果

请输入要订购的pizza种类:pepper北京胡椒披萨 准备原材料北京胡椒披萨 baking;北京胡椒披萨 cutting;北京胡椒披萨 boxing;请输入要订购的pizza种类:cheese北京奶酪披萨 准备原材料北京奶酪披萨 baking;北京奶酪披萨 cutting;北京奶酪披萨 boxing;请输入要订购的pizza种类:

3. 抽象工厂模式

3.1 什么是抽象工厂模式

抽象工厂模式:定义了一个interface用于创建相关或有依赖的对象簇,而无需指明具体的类抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)将工厂抽象成两次,AbsFactors(抽象工厂)和具体实现的工厂子类。程序与可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。

TIPS:

3.2 类图

3.3 代码实现

3.3.1 披萨类

package factory.factoryMethod.pizzastore.pizza;/*** @author LongXi* @create -07-31 8:47*///将Pizza做成抽象类public abstract class Pizza {//名字protected String name;//准备原材料,不同的披萨不一样,因此我们做成抽象方法public abstract void prepare();//烘烤public void bake(){System.out.println(name + " baking;");}public void cut(){System.out.println(name + " cutting;");}public void box(){System.out.println(name + " boxing;");}public void setName(String name){this.name = name;}}

3.3.2 4个实现类

/*** @author LongXi* @create -07-31 13:15*/public class BJCheesePizza extends Pizza{@Overridepublic void prepare() {setName("北京奶酪披萨");System.out.println("北京奶酪披萨 准备原材料");}}

/*** @author LongXi* @create -07-31 13:15*/public class BJPepperPizza extends Pizza{@Overridepublic void prepare() {setName("北京胡椒披萨");System.out.println("北京胡椒披萨 准备原材料");}}

/*** @author LongXi* @create -07-31 13:15*/public class LDCheesePizza extends Pizza{@Overridepublic void prepare() {setName("伦敦奶酪披萨");System.out.println("伦敦奶酪披萨 准备原材料");}}

/*** @author LongXi* @create -07-31 13:15*/public class LDPepperPizza extends Pizza{@Overridepublic void prepare() {setName("伦敦胡椒披萨");System.out.println("伦敦胡椒披萨 准备原材料");}}

3.3.3 抽象工厂接口

/*** @author LongXi* @create -07-31 14:21*///一个抽象工厂模式的抽象层(接口)public interface AbsFactory {//让下面的工厂子类来具体实现public Pizza cteatePizza (String orderType);}

3.3.4 两个重新工厂的实现类

/*** @author LongXi* @create -07-31 14:23*///这是一个工厂子类public class BJFactory implements AbsFactory{@Overridepublic Pizza cteatePizza(String orderType) {System.out.println("使用的抽象工厂模式");Pizza pizza = null;if (orderType.equals("cheese")){pizza = new BJCheesePizza();} else if (orderType.equals("pepper")){pizza = new BJPepperPizza();}return pizza;}}

/*** @author LongXi* @create -07-31 14:23*///这是一个工厂子类public class LDFactory implements AbsFactory{@Overridepublic Pizza cteatePizza(String orderType) {System.out.println("使用的抽象工厂模式");Pizza pizza = null;if (orderType.equals("cheese")){pizza = new LDCheesePizza();} else if (orderType.equals("pepper")){pizza = new LDPepperPizza();}return pizza;}}

3.3.5 订购披萨类

/*** @author LongXi* @create -07-31 14:27*/public class OrderPizza {public OrderPizza(AbsFactory absFactory){setFactory(absFactory);}AbsFactory factory;private void setFactory(AbsFactory factory){Pizza pizza = null;String orderType = "";this.factory = factory;do{orderType = getType();pizza = this.factory.cteatePizza(orderType);if (pizza != null){pizza.prepare();pizza.bake();pizza.cut();pizza.box();}else {System.out.println("订购失败");break;}}while(true);}//加一个方法,可以获取客户希望订购的披萨种类private String getType(){try {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));System.out.println("请输入要订购的pizza种类:");String str = null;str = br.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}}

3.3.6 披萨商店类

/*** @author LongXi* @create -07-31 14:35*/public class PizzaStore {public static void main(String[] args) {new OrderPizza(new BJFactory());new OrderPizza(new LDFactory());}}

3.3.7 运行结果

请输入要订购的pizza种类:cheese使用的抽象工厂模式北京奶酪披萨 准备原材料北京奶酪披萨 baking;北京奶酪披萨 cutting;北京奶酪披萨 boxing;请输入要订购的pizza种类:pepper使用的抽象工厂模式北京胡椒披萨 准备原材料北京胡椒披萨 baking;北京胡椒披萨 cutting;北京胡椒披萨 boxing;请输入要订购的pizza种类:chian使用的抽象工厂模式订购失败

4. 工厂模式JDK里的使用

日期类:Calendar

/*** @author LongXi* @create -07-31 14:47*/public class TestCalendar {public static void main(String[] args) {Calendar calendar = Calendar.getInstance();System.out.println(calendar.get(Calendar.YEAR));}}

DEBUG看核心代码:

public static Calendar getInstance(){return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));}

private static Calendar createCalendar(TimeZone zone,Locale aLocale){CalendarProvider provider =LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale).getCalendarProvider();if (provider != null) {try {return provider.getInstance(zone, aLocale);} catch (IllegalArgumentException iae) {// fall back to the default instantiation}}Calendar cal = null;if (aLocale.hasExtensions()) {String caltype = aLocale.getUnicodeLocaleType("ca");if (caltype != null) {switch (caltype) {case "buddhist":cal = new BuddhistCalendar(zone, aLocale);break;case "japanese":cal = new JapaneseImperialCalendar(zone, aLocale);break;case "gregory":cal = new GregorianCalendar(zone, aLocale);break;}}}if (cal == null) {// If no known calendar type is explicitly specified,// perform the traditional way to create a Calendar:// create a BuddhistCalendar for th_TH locale,// a JapaneseImperialCalendar for ja_JP_JP locale, or// a GregorianCalendar for any other locales.// NOTE: The language, country and variant strings are interned.if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {cal = new BuddhistCalendar(zone, aLocale);} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"&& aLocale.getCountry() == "JP") {cal = new JapaneseImperialCalendar(zone, aLocale);} else {cal = new GregorianCalendar(zone, aLocale);}}return cal;}

5. 工厂模式小结

工厂模式的意义

将实例化对象的代码提取出来,放到一个类中,统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。三种工厂模式设计模式的依赖抽象原则 创建对象实例,不要直接new类,而是把这个new类的动作放到一个工厂的方法中,并返回。有的书上说,变量不要直接持有具体类的引用。不要让类继承具体类,而是继承抽象类或者是实现interface(接口)不要覆盖基类中已经实现的方法。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。