从披萨店的案例引入工厂模式
披萨的种类很多(比如 GreekPizza、CheesePizza 等)
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。定义了一个创建对象的工厂类,由这个工厂类来封装实例化对象的代码。
在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式。
属于创建型模式。
设计方案: 定义一个可以实例化 Pizaa 对象的工厂类,封装创建对象的代码。
Pizza接口
- public interface Pizza {
-
- /**
- * 披萨切片
- */
- void cut();
-
- /**
- * 披萨包装
- */
- void box();
- }
奶酪披萨
- public class CheesePizza implements Pizza {
-
- public void cut() {
- System.out.println("奶酪披萨切片中");
- }
-
- public void box() {
- System.out.println("奶酪披萨打包中");
- }
- }
希腊披萨
- public class GreekPizza implements Pizza {
-
- public void cut() {
- System.out.println("希腊披萨切片中");
- }
-
- public void box() {
- System.out.println("希腊披萨打包中");
- }
- }
创建披萨实例的工厂
- public class PizzaFactory {
-
- public static Pizza getPizza(String type) {
- if(type.equalsIgnoreCase("CheesePizza")){
- return new CheesePizza();
- }else if(type.equalsIgnoreCase("GreekPizza")){
- return new GreekPizza();
- }else {
- return null;
- }
- }
-
- }
测试
- public class Client {
- public static void main(String[] args) {
- Pizza cheesePizza = PizzaFactory.getPizza("CheesePizza");
- cheesePizza.cut();
- cheesePizza.box();
-
- Pizza greekPizza = PizzaFactory.getPizza("GreekPizza");
- greekPizza.cut();
- greekPizza.box();
- }
- }
结果
奶酪披萨切片中
奶酪披萨打包中
希腊披萨切片中
希腊披萨打包中
看一个新的需求,客户在点披萨时,可以点不同口味的披萨,比如北京的奶酪 pizza、北京的胡椒 pizza 或者是伦敦的奶酪 pizza、伦敦的胡椒 pizza。
思路 1
使用简单工厂模式,创建不同的简单工厂类,比如 BJPizzaSimpleFactory,LDPizzaSimpleFactory等等。从当前这个案例来说,也是可以的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好。
思路 2
使用工厂方法模式
工厂方法模式:定义一个创建对象的抽象方法,由子类工厂决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
披萨类Pizza
- public interface Pizza {
-
- /**
- * 披萨切片
- */
- void cut();
-
- /**
- * 披萨包装
- */
- void box();
- }
四种披萨
- public class BJChessPizza implements Pizza{
-
- public void cut() {
- System.out.println("北京奶酪披萨切片中");
- }
-
- public void box() {
- System.out.println("北京奶酪披萨打包中");
- }
- }
- public class BJPepperPizza implements Pizza{
-
- public void cut() {
- System.out.println("北京胡椒披萨切片中");
- }
-
- public void box() {
- System.out.println("北京胡椒披萨打包中");
- }
- }
- public class LDChessPizza implements Pizza{
-
- public void cut() {
- System.out.println("伦敦奶酪披萨切片中");
- }
-
- public void box() {
- System.out.println("伦敦奶酪披萨打包中");
- }
- }
- public class LDPepperPizza implements Pizza{
-
- public void cut() {
- System.out.println("伦敦胡椒披萨切片中");
- }
-
- public void box() {
- System.out.println("伦敦胡椒披萨打包中");
- }
- }
Pizza抽象工厂
- public abstract class PizzaFactory {
-
- public abstract Pizza getPizza(String type);
-
- }
北京披萨工厂,伦敦披萨工厂
- public class BJPizzaFactory extends PizzaFactory {
- @Override
- public Pizza getPizza(String type) {
- if(type.equalsIgnoreCase("chess")){
- return new BJChessPizza();
- }else if(type.equalsIgnoreCase("pepper")){
- return new BJPepperPizza();
- }else {
- return null;
- }
- }
- }
- public class LDPizzaFactory extends PizzaFactory {
- @Override
- public Pizza getPizza(String type) {
- if(type.equals("chess")){
- return new LDChessPizza();
- }else if(type.equals("pepper")){
- return new LDPepperPizza();
- }else {
- return null;
- }
- }
- }
测试
- public class Client {
- public static void main(String[] args) {
- //北京披萨工厂
- BJPizzaFactory bjPizzaFactory = new BJPizzaFactory();
-
- Pizza bjChessPizza = bjPizzaFactory.getPizza("chess");
- bjChessPizza.cut();
- bjChessPizza.box();
-
- Pizza bjPepperPizza = bjPizzaFactory.getPizza("pepper");
- bjPepperPizza.cut();
- bjPepperPizza.box();
-
- //伦敦披萨工厂
- LDPizzaFactory ldPizzaFactory = new LDPizzaFactory();
-
- Pizza ldChessPizza = ldPizzaFactory.getPizza("chess");
- ldChessPizza.cut();
- ldChessPizza.box();
-
- Pizza ldPepperPizza = ldPizzaFactory.getPizza("pepper");
- ldPepperPizza.cut();
- ldPepperPizza.box();
- }
- }
结果
北京奶酪披萨切片中
北京奶酪披萨打包中
北京胡椒披萨切片中
北京胡椒披萨打包中
伦敦奶酪披萨切片中
伦敦奶酪披萨打包中
伦敦胡椒披萨切片中
伦敦胡椒披萨打包中
新需求:有的人喜欢吃肯德基的披萨,有的人喜欢吃麦当劳的披萨
抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类
披萨接口
- public interface Pizza {
-
- /**
- * 披萨切片
- */
- void cut();
-
- /**
- * 披萨包装
- */
- void box();
- }
商店A披萨,商店B披萨接口
- public interface ShopAPizza extends Pizza {
- }
- public interface ShopBPizza extends Pizza {
- }
商店A披萨的实现类
- public class ShopABJChessPizza implements ShopAPizza{
-
- public void cut() {
- System.out.println("商店A北京奶酪披萨切片中");
- }
-
- public void box() {
- System.out.println("商店A北京奶酪披萨打包中");
- }
- }
- public class ShopALDChessPizza implements ShopAPizza{
-
- public void cut() {
- System.out.println("商店A伦敦奶酪披萨切片中");
- }
-
- public void box() {
- System.out.println("商店A伦敦奶酪披萨打包中");
- }
- }
商店B披萨的实现类
- public class ShopBBJChessPizza implements ShopBPizza{
-
- public void cut() {
- System.out.println("商店B北京胡椒披萨切片中");
- }
-
- public void box() {
- System.out.println("商店B北京胡椒披萨打包中");
- }
-
- }
- public class ShopBLDChessPizza implements ShopBPizza{
-
- public void cut() {
- System.out.println("商店B伦敦胡椒披萨切片中");
- }
-
- public void box() {
- System.out.println("商店B伦敦胡椒披萨打包中");
- }
-
- }
披萨工厂抽象类
- public abstract class PizzaFactory {
-
- public abstract Pizza getBJChessPizza(String type);
-
- public abstract Pizza getLDChessPizza(String type);
- }
商店A,B的工厂类
- public class ShopAPizzaFactory extends PizzaFactory {
-
- @Override
- public Pizza getBJChessPizza(String type) {
- return new ShopABJChessPizza();
- }
-
- @Override
- public Pizza getLDChessPizza(String type) {
- return new ShopALDChessPizza();
- }
- }
- public class ShopBPizzaFactory extends PizzaFactory {
- @Override
- public Pizza getBJChessPizza(String type) {
- return new ShopBBJChessPizza();
- }
-
- @Override
- public Pizza getLDChessPizza(String type) {
- return new ShopBLDChessPizza();
- }
- }
比如说日历类Calendar就用到了简单工厂模式
我们一般这样使用
- public class Test {
- public static void main(String[] args) {
- Calendar cal = Calendar.getInstance();
- System.out.println("年:" + cal.get(Calendar.YEAR));
- System.out.println("月:" + (cal.get(Calendar.MONTH) + 1));
- System.out.println("日:" + cal.get(Calendar.DAY_OF_MONTH));
- System.out.println("时:" + cal.get(Calendar.HOUR_OF_DAY));
- System.out.println("分:" + cal.get(Calendar.MINUTE));
- System.out.println("秒:" + cal.get(Calendar.SECOND));
- }
- }
具体源码:就用到了简单工厂模式
- /**
- * Gets a calendar using the default time zone and locale. The
- *
Calendar
returned is based on the current time - * in the default time zone with the default
- * {@link Locale.Category#FORMAT FORMAT} locale.
- *
- * @return a Calendar.
- */
- public static Calendar getInstance()
- {
- return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
- }
- private static Calendar createCalendar(TimeZone zone,
- Locale aLocale)
- //根据 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;
- }
将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式
个人觉得这个区别在于产品,如果产品单一,最合适用工厂模式,但是如果有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。再通俗深化理解下:工厂模式针对的是一个产品等级结构 ,抽象工厂模式针对的是面向多个产品等级结构的。
再来看看工厂方法模式与抽象工厂模式对比:
工厂方法模式 | 抽象工厂模式 |
针对的是一个产品等级结构 | 针对的是面向多个产品等级结构 |
一个抽象产品类 | 多个抽象产品类 |
可以派生出多个具体产品类 | 每个抽象产品类可以派生出多个具体产品类 |
一个抽象工厂类,可以派生出多个具体工厂类 | 一个抽象工厂类,可以派生出多个具体工厂类 |
每个具体工厂类只能创建一个具体产品类的实例 | 每个具体工厂类可以创建多个具体产品类的实例 |