设计模式---工厂模式

目录

1、简单工厂模式

1.1 看一个具体的需求

1.2 使用传统的方式来完成

 1.3 传统方式的优缺点

1.4、基本介绍

1.5、使用简单工厂模式

2、工厂方法模式 

2.1 看一个新的需求

2.2 思路1

2.3 思路2

2.4 工厂方法模式介绍

2.5工厂方法模式应用案例

3、抽象工厂模式

3.1 基本介绍

3.2 类图

 5、工厂模式的总结


1、简单工厂模式

1.1 看一个具体的需求

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

  1. 披萨的种类很多(比如 GreekPizz、CheesePizz等)
  2. 披萨的制作有prepare,bake,cut,box
  3. 完成披萨店订购功能。

1.2 使用传统的方式来完成

  • 思路分析(类图)

抽象类Pizza

package com.mayun.study.designpattern.factory.simplefactory.pizzastore.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;
    }
}

 其中一种披萨:GreekPizza 其他的几个代码类似,这里就只贴一个:

package com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza;

public class GreekPizza extends Pizza{


    @Override
    public void prepare() {
        // TODO Auto-generated method stub
        System.out.println(" 给希腊披萨 准备原材料 ");
    }
}

编写OrderPizza去订购Pizza

package com.mayun.study.designpattern.factory.simplefactory.pizzastore.order;

import com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

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 制作过程
			pizza.prepare();
			pizza.bake();
			pizza.cut();
			pizza.box();

		} while (true);
	}

 

    

    // 写一个方法,可以获取客户希望订购的披萨种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

 定义一个测试类 PizzaStore

package com.mayun.study.designpattern.factory.simplefactory.pizzastore.order;

//相当于一个客户端,发出订购
public class PizzaStore {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new OrderPizza();
    }

}

 1.3 传统方式的优缺点

优点:比较好理解,简单易操作。

缺点:违反了设计模式的ocp原则,即对扩展开发,对修改关闭。即当我们给类增加新功能时,尽量不修改代码或者尽可能少修改代码,比如,我们要新增一个种类的pizza,则要在OrderPizza类的if判断中增加修改,这就违法了修改关闭,即要修改使用方的代码。

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

1.4、基本介绍

简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式。

简单工厂模式:定义了一个创建对象的工厂类,由这个类封装实例化对象的行为(代码)。

在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式。

1.5、使用简单工厂模式

简单工厂模式的设计方案:定义一个可以实例化Pizza对象的工厂类,封装创建对象的代码。

示例代码:

SimpleFactory

package com.mayun.study.designpattern.factory.simplefactory.pizzastore.order;

import com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza.Pizza;

//简单工厂类
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;
    }
}

package com.mayun.study.designpattern.factory.simplefactory.pizzastore.order;

import com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.mayun.study.designpattern.factory.simplefactory.pizzastore.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class OrderPizza {



    //构造函数
    public OrderPizza(SimpleFactory simpleFactory) {
        setSimpleFactory(simpleFactory);

    }

    SimpleFactory simpleFactory;
    Pizza pizza;
    public void setSimpleFactory(SimpleFactory simpleFactory) {
        String orderType = "";//用户输入需要订购的披萨类型

        this.simpleFactory = simpleFactory;
        do {
            orderType = getType();
            pizza = this.simpleFactory.createPizza(orderType);
            if (null != pizza) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else{
                System.out.println("订购披萨失败");
                break;
            }


        } while (true);
    }

    // 写一个方法,可以获取客户希望订购的披萨种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

2、工厂方法模式 

2.1 看一个新的需求

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

2.2 思路1

使用简单工厂模式,创建不同的简单工厂类,比如BJPizzaSimpleFactory、LDPizzaSimpleFactory等等,从当前这个案例来说,是可以的,但是考虑到项目的规模以及项目的可维护性,可扩展并不是特别好。

2.3 思路2

使用工厂方法模式。

2.4 工厂方法模式介绍

工厂方法模式设计方案:将披萨项目实例化功能抽象成抽象方法,在不同口味点餐子类中具体实现。

工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。

2.5工厂方法模式应用案例

这个思路的核心就是将对象的实例推迟到子类工厂中去完成。实例代码:

package com.mayun.study.designpattern.factory.methodfactory.pizzastore.pizza;

public class BJCheesePizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京的奶酪pizza");
        System.out.println(" 北京的奶酪pizza 准备原材料");
    }
}

OrderPizza转换成一个抽象类,作为基础工厂,其中定义创建对象的抽象方法:

package com.mayun.study.designpattern.factory.methodfactory.pizzastore.order;

import com.mayun.study.designpattern.factory.methodfactory.pizzastore.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public abstract class OrderPizza {
    //定义一个抽象方法,createPizza , 让各个工厂子类自己实现
    abstract Pizza createPizza(String orderType);

    // 构造器
    public OrderPizza() {
        Pizza pizza = null;
        String orderType; // 订购披萨的类型
        do {
            orderType = getType();
            pizza = createPizza(orderType); //抽象方法,由工厂子类完成(关键,将对象的实例化推迟到子类)
            //输出pizza 制作过程
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();

        } while (true);
    }



    // 写一个方法,可以获取客户希望订购的披萨种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

之后再定义各子工厂,继承OrderPizza,实现createPizza方法,完成对象的批量实例化

package com.mayun.study.designpattern.factory.methodfactory.pizzastore.order;

import com.mayun.study.designpattern.factory.methodfactory.pizzastore.pizza.BJCheesePizza;
import com.mayun.study.designpattern.factory.methodfactory.pizzastore.pizza.BJPepperPizza;
import com.mayun.study.designpattern.factory.methodfactory.pizzastore.pizza.Pizza;

public class BJOrderPizza extends OrderPizza {


    @Override
    Pizza createPizza(String orderType) {

        Pizza pizza = null;
        if(orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        // TODO Auto-generated method stub
        return pizza;
    }

}
package com.mayun.study.designpattern.factory.methodfactory.pizzastore.order;

import com.mayun.study.designpattern.factory.methodfactory.pizzastore.pizza.LDCheesePizza;
import com.mayun.study.designpattern.factory.methodfactory.pizzastore.pizza.LDPepperPizza;
import com.mayun.study.designpattern.factory.methodfactory.pizzastore.pizza.Pizza;

public class LDOrderPizza extends OrderPizza{
    @Override
    Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")) {
            pizza = new LDCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new LDPepperPizza();
        }
        // TODO Auto-generated method stub
        return pizza;
    }
}

最后就是使用工厂类了:

package com.mayun.study.designpattern.factory.methodfactory.pizzastore.order;

public class PizzaStore {

    public static void main(String[] args) {
        String loc = "bj";
        if (loc.equals("bj")) {
            //创建北京口味的各种Pizza
            new BJOrderPizza();
        } else {
            //创建伦敦口味的各种Pizza
            new LDOrderPizza();
        }
        // TODO Auto-generated method stub
    }

}

 这里再次强调一下:只要理解了对象实例化推迟到子类完成,这个就理解了。

3、抽象工厂模式

3.1 基本介绍

抽象工厂模式:定义了一个interface,用于创建相关或有依赖关系的对象簇,而无需指明具体的类。

抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。

从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者成为进一步的抽象)

将工厂抽象为两层,AbsFactory(抽象工厂)和具体实现的工厂子类,程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂变为了工厂簇,更利于代码的维护和扩展。

3.2 类图

3.3 应用场景实例

还是以上个工厂方法模式中的披萨项目为场景,代码如下:

pizza对象的代码与上面相同,这里就不贴了。

看几个核心的:

AbsFactory.java
package com.mayun.study.designpattern.factory.absfactor.pizzastore.order;

import com.mayun.study.designpattern.factory.absfactor.pizzastore.pizza.Pizza;

//一个抽象工程模式的抽象层接口
public interface AbsFactory {

    //让下面的具体的工厂子类具体实现
    public Pizza createPizza(String orderType);
}
BJFactory.java
package com.mayun.study.designpattern.factory.absfactor.pizzastore.order;

import com.mayun.study.designpattern.factory.absfactor.pizzastore.pizza.BJCheesePizza;
import com.mayun.study.designpattern.factory.absfactor.pizzastore.pizza.BJPepperPizza;
import com.mayun.study.designpattern.factory.absfactor.pizzastore.pizza.Pizza;

public class BJFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

LDFactory.java
package com.mayun.study.designpattern.factory.absfactor.pizzastore.order;

import com.mayun.study.designpattern.factory.absfactor.pizzastore.pizza.LDCheesePizza;
import com.mayun.study.designpattern.factory.absfactor.pizzastore.pizza.LDPepperPizza;
import com.mayun.study.designpattern.factory.absfactor.pizzastore.pizza.Pizza;

public class LDFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")) {
            pizza = new LDCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}
OrderPizza.java
package com.mayun.study.designpattern.factory.absfactor.pizzastore.order;


import com.mayun.study.designpattern.factory.absfactor.pizzastore.pizza.Pizza;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class OrderPizza {

    AbsFactory factory;

    // 构造器
    public OrderPizza(AbsFactory factory) {
        setFactory(factory);
    }

    private void setFactory(AbsFactory factory) {
        Pizza pizza = null;
        String orderType = ""; // 用户输入
        this.factory = factory;
        do {
            orderType = getType();
            // factory 可能是北京的工厂子类,也可能是伦敦的工厂子类
            pizza = factory.createPizza(orderType);
            if (pizza != null) { // 订购ok
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println("订购失败");
                break;
            }
        } while (true);
    }

    // 写一个方法,可以获取客户希望订购的披萨种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

PizzaStore.java
package com.mayun.study.designpattern.factory.absfactor.pizzastore.order;

public class PizzaStore {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //new OrderPizza(new BJFactory());
        new OrderPizza(new LDFactory());
    }

}

 4、工厂模式在JDK-Calendar中的源码应用

JDK Calendar就使用了简单工厂模式,

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;
    }

 5、工厂模式的总结

工厂模式的意义:

将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目依赖关系的解耦,从而提高项目的扩展和维护。

三种工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)

设计模式的依赖抽象原则。

  • 创建对象实例时,不要直接new类,而是把这个new类的动作放在一个工厂方法中,并返回。有的书上说,变量不要直接持有具体类的引用。
  • 不要让类继承具体类,而是继承抽象类或者实现接口。
  • 不要覆盖基类中已实现的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值