工厂模式
一、简单工厂模式
1.看一个具体的需要
有一个生产披萨的需求,要便于披萨种类的扩展,要便于维护
- 披萨种类很多
- 只做步骤分为prepare bake cut box
- 完成披萨的定个功能
2.使用传统的方式来完成
2.1思路分析

2.2代码
package com.slp.pattern.factory.v1;
/**
* @ClassName Pizza
* @Description TODO
* @Author sanglp
* @Date 2020/8/17 13:00
* @Version 1.0
**/
public abstract class Pizza {
private String name;
public abstract void prepare();
public void bake(){
System.out.println(name+" bake");
}
public void cut(){
System.out.println(name+" cut");
}
public void box(){
System.out.println(name+" box");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.slp.pattern.factory.v1;
/**
* @ClassName GreekPizza
* @Description TODO
* @Author sanglp
* @Date 2020/8/17 13:02
* @Version 1.0
**/
public class GreekPizza extends Pizza {
@Override
public void prepare() {
System.out.println("prepare GreekPizza");
}
}
package com.slp.pattern.factory.v1;
/**
* @ClassName ChinaPizza
* @Description TODO
* @Author sanglp
* @Date 2020/8/17 13:02
* @Version 1.0
**/
public class ChinaPizza extends Pizza {
@Override
public void prepare() {
System.out.println("prepare ChinaPizza");
}
}
package com.slp.pattern.factory.v1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
/**
* @ClassName OrderPizza
* @Description TODO
* @Author sanglp
* @Date 2020/8/17 12:58
* @Version 1.0
**/
public class OrderPizza {
public static void main(String[] args) {
OrderPizza orderPizza = new OrderPizza();
}
public OrderPizza(){
Pizza pizza = null;
String orderType ;//订购的类型
do{
orderType=getType();
if(orderType.equals("greek")){
pizza = new GreekPizza();
pizza.setName("希腊披萨");
}else if(orderType.equals("china")){
pizza = new ChinaPizza();
pizza.setName("中国披萨");
}else {
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}while (true);
}
/**
* pizza种类从控制台输入
* @return
*/
private String getType() {
BufferedReader s = new BufferedReader(new InputStreamReader(System.in));
String str = null;
try {
str = s.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
}
2.3 传统方式的优缺点
- 优点是比较好理解,简单易操作
- 缺点是违反了设计模式的ocp原则,及对扩展开发,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者是少修改代码。
- 比如我们此时需要新增加一个种类,那么orderPizza中需要新增分支
2.4 改进思路
修改代码可以接受,但是如果我们在其他的地方也有创建的代码 ,就意味着,也需要修改,而创建pizza的代码,往往会有很多。也就是说有很多类都在调用这个方法。
这样的话,我们可以将创建pizza对象封装到一个类中,这样我们有新的pizza种类的时候,只需要修改该类即可,这样其他创建到pizza对的diam就不需要修改了
这也就是简单工厂模式
3.简单工厂模式基本介绍
简单工厂模式属于创建型模式,是工厂模式的一种,简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,简单工厂模式是工厂模式中最简单实用的模式。
简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为
在软件开发中,当我们会用到大量的创建某种、某类或某批对象时,就会使用到工厂模式。
3.1 使用简单工厂模式
-
定义一个可以实例化Pizza对象的类,封装创建对象的代码

-
示例代码
package com.slp.pattern.factory.v2;
/**
* @ClassName SimpleFactory
* @Description 简单工厂模式
* @Author sanglp
* @Date 2020/8/17 13:56
* @Version 1.0
**/
public class SimpleFactory {
public Pizza createPizza(String orderType){
Pizza pizza = null;
if(orderType.equals("greek")){
pizza = new GreekPizza();
pizza.setName("希腊披萨");
}else if(orderType.equals("china")){
pizza = new ChinaPizza();
pizza.setName("中国披萨");
}else {
System.out.println("输入有误");
}
return pizza;
}
/**
* 简单工厂模式,也叫静态工厂模式
* @param orderType
* @return
*/
public static Pizza createPizzav2(String orderType){
Pizza pizza = null;
System.out.println("使用简单工厂模式2");
if(orderType.equals("greek")){
pizza = new GreekPizza();
pizza.setName("希腊披萨");
}else if(orderType.equals("china")){
pizza = new ChinaPizza();
pizza.setName("中国披萨");
}else {
System.out.println("输入有误");
}
return pizza;
}
}
package com.slp.pattern.factory.v2;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @ClassName OrderPizza
* @Description TODO
* @Author sanglp
* @Date 2020/8/17 14:01
* @Version 1.0
**/
public class OrderPizza {
//定义一个简单工厂
SimpleFactory simpleFactory;
Pizza pizza = null;
//构造器
public OrderPizza(SimpleFactory simpleFactory){
setFactory(simpleFactory);
}
public void setFactory(SimpleFactory simpleFactory){
String orderType = "";
this.simpleFactory = simpleFactory;//设置简单工厂对象
do{
orderType = getType();
pizza = this.simpleFactory.createPizza(orderType);
if(pizza!=null) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else {
System.out.println("订购失败");
}
}while (true);
}
/**
* pizza种类从控制台输入
* @return
*/
private String getType() {
BufferedReader s = new BufferedReader(new InputStreamReader(System.in));
String str = null;
try {
str = s.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
}
二、工厂方法模式
1.看一个新的需求
还是上面的案例,但是现在客户在点pizza的时候可以点不同口味的披萨,比如北京的奶酪pizza,北京的胡椒pizza或者伦敦的奶酪pizza,伦敦的胡椒pizza
2.思路一
使用简单工厂模式,创建不同的简单工厂类,比如BJPizzaSimpleFactory.LDPizzaSimpleFactory等等,从当前这个案例来说,也是可以的。但是考虑更久远一些的话其实并不太好。
3.思路二
使用工厂方法模式
4.工厂方法模式介绍
- 工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现
- 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类,工厂方法模式将对象的实例推迟到子类
5.工厂方法模式应用案例

package com.slp.pattern.factory.v3;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @ClassName OrderPizza
* @Description TODO
* @Author sanglp
* @Date 2020/8/17 16:34
* @Version 1.0
**/
public abstract class OrderPizza {
/**
* 定义一个抽象方法,让各个工厂类去实现
* @param orderType
* @return
*/
abstract Pizza createPizza(String orderType);
public OrderPizza(){
Pizza pizza = null;
String orderType;//订购pizza的类型
do{
orderType = getType();
pizza = createPizza(orderType);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}while (true);
}
protected String getType(){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String orderType = null;
try {
orderType = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return orderType;
}
}
package com.slp.pattern.factory.v3;
/**
* @ClassName BJOrderPizza
* @Description TODO
* @Author sanglp
* @Date 2020/8/17 16:38
* @Version 1.0
**/
public class BJOrderPizza extends OrderPizza {
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if(orderType.equals("cheese")){
pizza = new BJCheesePizza();
pizza.setName("bjcheese");
}else if(orderType.equals("pepper")){
pizza = new BJPepperPizza();
pizza.setName("bjpepper");
}
return pizza;
}
}
package com.slp.pattern.factory.v3;
/**
* @ClassName LDOrderPizza
* @Description TODO
* @Author sanglp
* @Date 2020/8/17 16:42
* @Version 1.0
**/
public class LDOrderPizza extends OrderPizza {
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if(orderType.equals("perper")){
pizza = new LDGreekPizza();
}
return pizza;
}
}
三、抽象工厂模式
1.基本介绍
- 抽象工厂模式:定义了一个interface用于创建相关或者依赖关系的对象,无需指明具体的类
- 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合
- 从设计层面看,抽象工厂模式就是对简单工厂模式的改进,或者是进一步的抽象
- 将工厂抽象成两层,AbsFactory(抽象工厂)和具体实现的工厂子类,而我们可以根据创建对象类型使用相应的工厂子类,这样将单个的简单工厂类变成了工厂簇,更有利于代码的维护和扩展

#### 2.示例
package com.slp.pattern.factory.v4;
/**
* 抽象工厂模式的抽象层 解决
*/
public interface AbsFactory {
/**
* 让工厂子类来具体实现
* @param orderType
* @return
*/
public Pizza createPizza(String orderType);
}
package com.slp.pattern.factory.v4;
public class BJFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
System.out.println("输入为:"+orderType);
Pizza pizza = null;
if(orderType.equals("cheese")){
pizza = new BJCheesePizza();
}else if(orderType.equals("pepper")){
pizza = new BJPepperPizza();
}else {
System.out.println("输入有误");
}
return pizza;
}
}
package com.slp.pattern.factory.v4;
public class LDFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if(orderType.equals("cheese")){
pizza = new LDCheessPizza();
}else if(orderType.equals("pepper")){
pizza = new LDGreekPizza();
}else {
System.out.println("输入有误");
}
return pizza;
}
}
package com.slp.pattern.factory.v4;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class OrderPizza {
public OrderPizza(AbsFactory factory){
setFactory(factory);
}
AbsFactory factory;
private void setFactory(AbsFactory absFactory){
Pizza pizza = null;
factory = absFactory;
do{
String orderType = getType();
//factory可能是北京工厂子类 也可能是伦敦工厂子类
pizza = factory.createPizza(orderType);
if (pizza!=null) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else {
break;
}
}while (true);
}
protected String getType(){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String orderType = null;
try {
orderType = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return orderType;
}
}
package com.slp.pattern.factory.v4;
/**
* 抽象工厂模式
*/
public class Test {
public static void main(String[] args) {
new OrderPizza(new BJFactory());
}
}
四、应用
1. JDK中的Calendar类中,就使用了简单工厂模式
package com.slp.pattern.factory.use;
import java.util.Calendar;
public class Factory {
public static void main(String[] args) {
//getInstance是一个静态方法
Calendar cal = Calendar.getInstance();
System.out.println(cal.get(Calendar.YEAR));
}
}
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;
}
五、工厂模式小结
1.工厂模式的意义
将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦,从而提高项目的扩展和维护性
2.三种工厂模式
简单工厂 、工厂方法 、抽象工厂
3.设计模式的依赖抽象原则
- 创建对象实例时,不要直接new类,而是把这个new类的动作放在一个工厂的方法中,并返回,也有的说,变量不要直接持有具体的引用
- 不要让类继承具体类,而是继承抽象类或者是实现接口
- 不要覆盖类中已经实现的方法
8万+



被折叠的 条评论
为什么被折叠?



