使用Java语言编写设计模式-5.创建型模式-简单工厂模式(Gof之外)

lingwh原创2022年9月8日大约 7 分钟约 2111 字

5.创建型模式-简单工厂模式(Gof之外)

5.1.章节内容概述

本章节涉及主要内容有:
 5.1.章节内容概述
 5.2.章节内容大纲
 5.3.简介
 5.4.应用场景
 5.5.优缺点
 5.6.角色及其职责
 5.7.模型
 5.8.示例
 5.9.在开源框架中的应用
 5.9.1.在JDK中的应用
具体每个小节中包含的内容可使通过下面的章节内容大纲进行查看。

5.2.章节内容大纲

5.3.简介

简单工厂模式(SimpleFactory Pattern)是一种创建型设计模式,是设计模式中最为常见的模式之一,但是不是Gof提出的23中设计模式中的一种,更像是一种编程习惯。简单工厂模式是隐藏对象的实例化过程,对外部提供一个获取对象的方法,可以根据参数获取不同类型的对象,是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

5.4.应用场景

a.客户端如果只知道传入工厂类得参数,对于如何创建对象得逻辑不关心时
b.客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应得参数
c.工厂负责创建的类少,同时系统中需要的new对象较多而且复杂时可以使用,这样一方面不会造成工厂方法中得业务逻辑太过复杂,另一方面在使用时不用一直new,直接从工厂中获取即可

5.5.优缺点

5.5.1.优点

a.屏蔽了具体的创建逻辑,客户端只需要要传入一个参数即可获取相应的结果,在一定程度上简化了对象的创建过程
b.将实例创建过程和使用过程分离开来,实现了解耦

5.5.2.缺点

a.工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响
b.违背OCP原则,一旦添加新产品就不得不修改工厂类得逻辑,这样就会造成工厂逻辑过于复杂
c.简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构

5.6.角色及其职责

Factory(工厂)
核心部分,负责实现创建所有产品的内部逻辑,工厂类可以被外界直接调用,创建所需对象
Product(抽象类产品)
工厂类所创建的所有对象的父类,封装了产品对象的公共方法,所有的具体产品为其子类对象
ConcreteProduct(具体产品)
简单工厂模式的创建目标,所有被创建的对象都是某个具体类的实例,它要实现抽象产品中声明的抽象方法(有关抽象类)

5.7.模型

5.7.1.模型类图

模型类图(有Client)
模型类图(无Client)

5.7.2.模型代码

Product.java
package com.dragonsoft.designpattern.create.factory.simplefactory.model;

/**
 * Product(抽象产品)
 */
public abstract class Product {
}

ConcreteProductA.java
package com.dragonsoft.designpattern.create.factory.simplefactory.model;

/**
 * ConcreteProductA(具体产品A)
 */
public class ConcreteProductA extends Product {
}

ConcreteProductB.java
package com.dragonsoft.designpattern.create.factory.simplefactory.model;

/**
 * ConcreteProductB(具体产品B)
 */
public class ConcreteProductB extends Product {
}

ConcreteProductC.java
package com.dragonsoft.designpattern.create.factory.simplefactory.model;

/**
 * ConcreteProductC(具体产品C)
 */
public class ConcreteProductC extends Product {
}

Factory.java
package com.dragonsoft.designpattern.create.factory.simplefactory.model;

/**
 * Factory(简单工厂)
 */
public class Factory {
    /**
     * 通过工厂方法生产产品
     * @param productType
     * @return
     */
    public Product factoryMethod(String productType) {
        Product product = null;
        if (productType.equals("productA")) {
            product = new ConcreteProductA();
        } else if (productType.equals("productB")) {
            product = new ConcreteProductB();
        } else if (productType.equals("productC")) {
            product = new ConcreteProductC();
        }
        return product;
    }

    /**
     * 调用工厂方法的方法
     * @param productType
     */
    public void operate(String productType){
        Product product = factoryMethod(productType);
        System.out.println(product);
    }
}

Client.java
package com.dragonsoft.designpattern.create.factory.simplefactory.model;

import org.junit.Test;

/**
 * Client(客户端)
 */
public class Client {

    @Test
    public void fun() {
        Factory factory = new Factory();
        //生产产品A
        Product productA = factory.factoryMethod("productA");
        System.out.println(productA);
        //在工厂中直接调用工厂方法
        factory.operate("productA");

        System.out.println("--------------------");
        //生产产品B
        Product productB = factory.factoryMethod("productB");
        System.out.println(productB);
        //在工厂中直接调用工厂方法
        factory.operate("productB");

        System.out.println("--------------------");
        //生产产品C
        Product productC = factory.factoryMethod("productC");
        System.out.println(productC);
        //在工厂中直接调用工厂方法
        factory.operate("productC");
    }
}

5.8.示例

5.8.1.不使用简单工厂模式

5.8.1.1.类图

类图(有Client)
类图(无Client)

5.8.1.2.代码

Pizza.java
package com.dragonsoft.designpattern.create.factory.simplefactory.nouse;

import java.util.ArrayList;

public abstract class Pizza {
	protected String name;
	protected String dough;
	protected String sauce;
	protected ArrayList<String> toppings = new ArrayList<String>();
	
	public void prepare() {
		System.out.println("preparing..." + this.name);
	}
	
	public void bake() {
		System.out.println("baking..." + this.name);
	}
	
	public void cut() {
		System.out.println("cutting..." + this.name);
	}
	
	public void box() {
		System.out.println("boxing..." + this.name);
	}

	@Override
	public String toString() {
		StringBuilder pizza = new StringBuilder();
		pizza.append("------" + name + "------\n");
		pizza.append("dough:" + dough + "\n");
		pizza.append("sauce:" + sauce + "\n");
		pizza.append("toppings:\n");
		for(String topping:toppings) {
			pizza.append(topping+"\n");
		}
		return String.valueOf(pizza);
	}
	
}

CheesePizza.java
package com.dragonsoft.designpattern.create.factory.simplefactory.nouse;

public class CheesePizza extends Pizza {
	public CheesePizza() {
		name = "Cheese Pizza";
		dough = "Regular Crust";
		sauce = "Marinara Pizza Sauce";
		toppings.add("Fresh Mozzarella");
		toppings.add("Parmesan");
	}
}

ClamPizza.java
package com.dragonsoft.designpattern.create.factory.simplefactory.nouse;

public class ClamPizza extends Pizza {
	public ClamPizza() {
		name = "Clam Pizza";
		dough = "Thin crust";
		sauce = "White garlic sauce";
		toppings.add("Clams");
		toppings.add("Grated parmesan cheese");
	}
}

PepperoniPizza.java
package com.dragonsoft.designpattern.create.factory.simplefactory.nouse;

public class PepperoniPizza extends Pizza {
	public PepperoniPizza() {
		name = "Pepperoni Pizza";
		dough = "Crust";
		sauce = "Marinara sauce";
		toppings.add("Sliced Pepperoni");
		toppings.add("Sliced Onion");
		toppings.add("Grated parmesan cheese");
	}
}

PizzaStore.java
package com.dragonsoft.designpattern.create.factory.simplefactory.nouse;

public class PizzaStore {

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

Client.java
package com.dragonsoft.designpattern.create.factory.simplefactory.nouse;

import org.junit.Test;

public class Client {
	
	@Test
	public void fun() {
		PizzaStore pizzaStore = new PizzaStore();
		Pizza cheesePizza = pizzaStore.orderPizza(new CheesePizza());
		System.out.println(cheesePizza);
		Pizza pepperoniPizza = pizzaStore.orderPizza(new PepperoniPizza());
		System.out.println(pepperoniPizza);
		Pizza clamPizza = pizzaStore.orderPizza(new ClamPizza());
		System.out.println(clamPizza);
	}

}

5.8.2.使用简单工厂模式

5.8.2.1.类图

类图(有Client)
类图(无Client)

5.8.2.2.代码

Pizza.java
package com.dragonsoft.designpattern.create.factory.simplefactory.use;

import java.util.ArrayList;

public abstract class Pizza {
	protected String name;
	protected String dough;
	protected String sauce;
	protected ArrayList<String> toppings = new ArrayList<String>();
	
	public void prepare() {
		System.out.println("preparing..." + this.name);
	}
	
	public void bake() {
		System.out.println("baking..." + this.name);
	}
	
	public void cut() {
		System.out.println("cutting..." + this.name);
	}
	
	public void box() {
		System.out.println("boxing..." + this.name);
	}

	@Override
	public String toString() {
		StringBuilder pizza = new StringBuilder();
		pizza.append("------" + name + "------\n");
		pizza.append("dough:" + dough + "\n");
		pizza.append("sauce:" + sauce + "\n");
		pizza.append("toppings:\n");
		for(String topping:toppings) {
			pizza.append(topping+"\n");
		}
		return String.valueOf(pizza);
	}
	
}

CheesePizza.java
package com.dragonsoft.designpattern.create.factory.simplefactory.use;

public class CheesePizza extends Pizza{
	public CheesePizza() {
		name = "Cheese Pizza";
		dough = "Regular Crust";
		sauce = "Marinara Pizza Sauce";
		toppings.add("Fresh Mozzarella");
		toppings.add("Parmesan");
	}
}

ClamPizza.java
package com.dragonsoft.designpattern.create.factory.simplefactory.use;

public class ClamPizza extends Pizza{
	public ClamPizza() {
		name = "Clam Pizza";
		dough = "Thin crust";
		sauce = "White garlic sauce";
		toppings.add("Clams");
		toppings.add("Grated parmesan cheese");
	}
}

PepperoniPizza.java
package com.dragonsoft.designpattern.create.factory.simplefactory.use;

public class PepperoniPizza extends Pizza{
	public PepperoniPizza() {
		name = "Pepperoni Pizza";
		dough = "Crust";
		sauce = "Marinara sauce";
		toppings.add("Sliced Pepperoni");
		toppings.add("Sliced Onion");
		toppings.add("Grated parmesan cheese");
	}
}

PizzaStoreFactory.java
package com.dragonsoft.designpattern.create.factory.simplefactory.use;

public class PizzaStoreFactory {

	/**
	 * 通过工厂方法生产产品
	 * @param pizzaType
	 * @return
	 */
	public Pizza createPizza(String pizzaType) {
		Pizza pizza = null;
		if (pizzaType.equals("cheese")) {
			pizza = new CheesePizza();
		} else if (pizzaType.equals("pepperoni")) {
			pizza = new PepperoniPizza();
		} else if (pizzaType.equals("clam")) {
			pizza = new ClamPizza();
		} 
		return pizza;
	}

	/**
	 * 调用工厂方法的方法
	 * @param pizzaType
	 * @return
	 */
	public Pizza orderPizza(String pizzaType) {
		Pizza pizza = createPizza(pizzaType);
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();
		return pizza;
	}
}

Client.java
package com.dragonsoft.designpattern.create.factory.simplefactory.use;

import org.junit.Test;

public class Client {
	
	@Test
	public void fun() {
		PizzaStoreFactory pizzaFactory = new PizzaStoreFactory();
		Pizza cheesePizza = pizzaFactory.orderPizza("cheese");
		System.out.println(cheesePizza);
		Pizza pepperoniPizza = pizzaFactory.orderPizza("pepperoni");
		System.out.println(pepperoniPizza);
		Pizza clamPizza = pizzaFactory.orderPizza("clam");
		System.out.println(clamPizza);
	}

}

5.9.在开源框架中的应用

5.9.1.在JDK中的应用

JDK8#java.util.Calendar
说明
其中的createCalendar()方法根据传入参数的不同创建出不同的Calendar抽象类的子类,也就是根据传入参数的不同创建出了不同的对象,对调用这个方法的方法而言,屏蔽了具体的创建过程,只需要传入参数即可获取对象,符合简单工厂模式要求

类图
代码
public abstract class Calendar {
    public static Calendar getInstance()
    {
        return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
    }

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

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

    public static Calendar getInstance(TimeZone zone,
                                       Locale aLocale)
    {
        return createCalendar(zone, aLocale);
    }

    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;
    }
    ...
}
可以看出,在getInstance()方法中调用了createCalendar()方法,只需要传入zone, aLocale,就可以获得一个Calendar对象
上次编辑于: 2022/9/10 01:42:04
贡献者: lingwh
评论