从披萨店的案例引入工厂模式
披萨的种类很多(比如 GreekPizza、CheesePizza 等)
- 披萨制作完成后需要进行cut(切片工作),box(包装工作)
- 完成披萨店的功能
一、简单工厂模式
1、基本介绍
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。定义了一个创建对象的工厂类,由这个工厂类来封装实例化对象的代码。
在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式。
属于创建型模式。
2、代码实现
设计方案: 定义一个可以实例化 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
使用工厂方法模式
1、基本介绍
工厂方法模式:定义一个创建对象的抽象方法,由子类工厂决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
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();
}
}
结果
北京奶酪披萨切片中
北京奶酪披萨打包中
北京胡椒披萨切片中
北京胡椒披萨打包中
伦敦奶酪披萨切片中
伦敦奶酪披萨打包中
伦敦胡椒披萨切片中
伦敦胡椒披萨打包中
三、抽象工厂模式
新需求:有的人喜欢吃肯德基的披萨,有的人喜欢吃麦当劳的披萨
1、基本介绍
抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类
2、代码实现
披萨接口
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();
}
}
四、JDK中的工厂模式源码案例
比如说日历类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
* <code>Calendar</code> 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;
}
五、工厂模式小结
1、工厂模式的意义
将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式
2、三种工厂模式 (简单工厂模式、工厂方法模式、抽象工厂模式)
个人觉得这个区别在于产品,如果产品单一,最合适用工厂模式,但是如果有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。再通俗深化理解下:工厂模式针对的是一个产品等级结构 ,抽象工厂模式针对的是面向多个产品等级结构的。
再来看看工厂方法模式与抽象工厂模式对比:
工厂方法模式 | 抽象工厂模式 |
针对的是一个产品等级结构 | 针对的是面向多个产品等级结构 |
一个抽象产品类 | 多个抽象产品类 |
可以派生出多个具体产品类 | 每个抽象产品类可以派生出多个具体产品类 |
一个抽象工厂类,可以派生出多个具体工厂类 | 一个抽象工厂类,可以派生出多个具体工厂类 |
每个具体工厂类只能创建一个具体产品类的实例 | 每个具体工厂类可以创建多个具体产品类的实例 |