23种设计模式之工厂模式

277 阅读5分钟

「这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战

介绍:

这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

优点:

1、一个调用者想创建一个对象,只要知道其名称就可以了。

2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。

3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:

每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

简单工厂模式

基本介绍

1)简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类

的实例。简单工厂模式是工厂模式家族中最简单实用的模式

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

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

传统建造披萨的方式:

image-20211106114344634

package com.jxau.simplefactory.pizzastore.order;

import com.jxau.simplefactory.pizzastore.pizza.CherresPizza;
import com.jxau.simplefactory.pizzastore.pizza.PepperPizza;
import com.jxau.simplefactory.pizzastore.pizza.Pizza;

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

public class OrderPizza {

    private Pizza pizza;

    public OrderPizza(){

            do{
                String type=gettype();
                if("芝士".equals(type)){
                    pizza=new CherresPizza();
                    pizza.setName("芝士");
                }else if("胡椒".equals(type)){
                    pizza=new PepperPizza();
                    pizza.setName("胡椒");
                }else{
                    break;
                }
                pizza.prepare();
                pizza.cut();
                pizza.back();

            }while (true);
    }

    public String gettype() {

        String type= null;
        try {
            BufferedReader strign=new BufferedReader(new InputStreamReader(System.in));
            System.out.println("请输入你想订购的披萨:");
            type = strign.readLine();
            return type;
        } catch (IOException e) {
            e.printStackTrace();
            return " ";
        }
        
    }

}

传统的方式的优缺点 1)优点是比较好理解,简单易操作。

2)缺点是违反了设计模式的ocp原则,即对==扩展开放,对修改关闭==。即当我们给类增加新功能的时候,尽量不修

改代码,或者尽可能少修改代码.

3)比如我们这时要新增加一个Pizza的种类(Pepper 披萨),我们需要做出繁琐的修改

改进的思路分析

分析:修改代码可以接受,但是如果我们在其它的地方也有创建Pizza的代码,就意味着,也需要修改,而创建Pizza的代码,往往有多处。

思路:把创建Pizza对象封装到一个类中,这样我们有新的Pizza种类时,只需要修改该类就可,其它有创建到Pizza

对象的代码就不需要修改了->简单工厂模式

image-20211106114327810

package com.jxau.simplefactory.pizzastore.order;

import com.jxau.simplefactory.pizzastore.pizza.CherresPizza;
import com.jxau.simplefactory.pizzastore.pizza.PepperPizza;
import com.jxau.simplefactory.pizzastore.pizza.Pizza;

public class SimplePizzaFactory {

    private Pizza pizza=null;

    public Pizza doPizza(String type) {

            if ("芝士".equals(type)) {
                pizza = new CherresPizza();
                pizza.setName("芝士");
            } else if ("胡椒".equals(type)) {
                pizza = new PepperPizza();
                pizza.setName("胡椒");
            } else {
                return null;

            }
            pizza.prepare();
            pizza.cut();
            pizza.back();
            return pizza;

    }
}


public class OrderPizzaTest02 {

    private SimplePizzaFactory simplePizzaFactory;
    private Pizza pizza;

    public void setSimplePizzaFactory(SimplePizzaFactory simplePizzaFactory) {

        this.simplePizzaFactory = simplePizzaFactory;
        do{
            String type=gettype();
            pizza=simplePizzaFactory.doPizza(type);
            if(pizza!=null) System.out.println("你的"+pizza.getName()+"已经完成!");
            else {System.out.println("暂无此披萨销售!");break;}
        }while (true);

    }

    public OrderPizzaTest02(SimplePizzaFactory simplePizzaFactory){
        setSimplePizzaFactory(simplePizzaFactory);
    }
}

工厂方法模式:

工厂枋法模式介绍

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

工厂方法模式设计方案:

将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。

umi类图:

image-20211106140509670

public abstract class OrderPizza {

    public OrderPizza(){
        Pizza pizza=null;

        do{
            String type=gettype(); // 订购披萨的类型
            pizza=getPizza(type);// 抽象方法,由工厂子类完成
            if(pizza==null){
                System.out.println("暂无你需要订购的类型");
                break;
            }else{
                pizza.prepare();
                pizza.back();
                pizza.cut();
            }

        }while (true);

    }

    public abstract Pizza getPizza(String type);
    
}


public class BjOrderPizza extends OrderPizza {

    private Pizza pizza=null;
    @Override
    public Pizza getPizza(String type) {
        if("芝士".equals(type)){
            pizza=new LondCheresPizza();
            pizza.setName("北京芝士");
        }else if("胡椒".equals(type)){
            pizza=new LondPepperPizza();
            pizza.setName("北京胡椒");
        }else{
            return null;
        }
        return pizza;
    }
}

抽象工厂模式:

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

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

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

4)将工厂抽象成两层,AbsFactory(抽象工厂)和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工

厂子类。

umi类图

image-20211106152536500

相比于之前的工厂方法模式,这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。

public interface AbsPizzaFactory {

    public Pizza cretatePizza(String type);
}


public class BjFactory implements AbsPizzaFactory {

    Pizza pizza=null;
    @Override
    public Pizza cretatePizza(String type) {

        if("芝士".equals(type)){
            pizza=new BjCheresPizza();
        }else if("胡椒".equals(type)){
            pizza=new BjPepperPizza();
        }else {
            return null;
        }
        return pizza;
    }
}

public class OrderPizza {

    private AbsPizzaFactory absPizzaFactory;
    private Pizza pizza=null;

    public OrderPizza(AbsPizzaFactory absPizzaFactory) {
        setAbsPizzaFactory(absPizzaFactory);
    }
    private void setAbsPizzaFactory(AbsPizzaFactory absPizzaFactory){


        this.absPizzaFactory=absPizzaFactory;
        do {
            String type=gettype();
            pizza = absPizzaFactory.cretatePizza(type);
            if(pizza!=null){
                pizza.prepare();
                pizza.back();
                pizza.cut();
                System.out.println("你订购的披萨已出炉!");
            }else{
                System.out.println("暂无此类披萨销售!");
                break;
            }
        }while (true);


    }

工厂模式在JDK源码中的应用:

Calendar.getInstance();// 日期类静态方法获取一个实例

public static Calendar getInstance()
    {
        Locale aLocale = Locale.getDefault(Locale.Category.FORMAT);
        return createCalendar(defaultTimeZone(aLocale), aLocale);
    }

		// 使用简单工厂模式
 public static Locale getDefault(Locale.Category category) {
        // do not synchronize this method - see 4071298
        switch (category) {// 根据传入的类型返回对应的Locale对象实例
        case DISPLAY:
            if (defaultDisplayLocale == null) {
                synchronized(Locale.class) {
                    if (defaultDisplayLocale == null) {
                        defaultDisplayLocale = initDefault(category);
                    }
                }
            }
            return defaultDisplayLocale;
        case FORMAT:
            if (defaultFormatLocale == null) {
                synchronized(Locale.class) {
                    if (defaultFormatLocale == null) {
                        defaultFormatLocale = initDefault(category);
                    }
                }
            }
            return defaultFormatLocale;
        default:
            assert false: "Unknown Category";
        }
        return getDefault();
    }

小结:

工厂模式的意义

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

目的扩展和维护性。

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

3)设计模式的依赖抽象原则

  • 创建对象实例时,不要直接new类,而是把这个new类的动作放在一个工厂的方法中,并返回。有的书上说,变量不要直接持有具体类的引用。

  • 不要让类继承具体类,而是继承抽象类或者是实现interface(接口)

  • 不要覆盖基类中已经实现的方法。