设计模式之----工厂模式及抽象工厂模式

设计模式之工厂模式及抽象工厂模式

  • 工厂方法模式以及抽象工厂模式
  • 工厂模式案例一
  • 工厂模式案例二
  • 小结

工厂方法模式以及抽象工厂模式

  • 工厂方法 : 定义一个创建对象的接口(抽象方法),让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程(实例化)延迟到子类进行。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
  • 抽象工厂: 提供一个创建一系列相关或相互依赖对象的接口(对象族),而无需指定它们具体的类。抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

工厂模式案例一

通过烘烤披萨并且完善相关的订单系统来看工厂模式,披萨有各种各样的,用户通过点不同的披萨,后台不断的完成相应的工作,即准备相应的披萨、烘烤、切片、打包。

这里写图片描述

(1)首先看一个不好的设计方案 :

这里写图片描述
各种Pizza类的父类

package factory.Bad.pizza;
/**
 * Pizza超类
 */
public abstract class Pizza {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return 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 !");
    }
}

然后是几个Pizza子类:

package factory.Bad.pizza;

public class CheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("CheesePizza");
        System.out.println(getName() + "  preparing!");
    }
}
package factory.Bad.pizza;

public class GreekPizza extends Pizza {
    @Override
    public void prepare() {
        setName("GreekPizza");
        System.out.println(getName() + "  preparing!");
    }
}
package factory.Bad.pizza;

public class PepperPizza extends Pizza {
    @Override
    public void prepare() {
        setName("PepperPizza");
        System.out.println(getName() + "  preparing!");
    }
}

然后是下单的类:

package factory.Bad.order;

import factory.Bad.pizza.CheesePizza;
import factory.Bad.pizza.GreekPizza;
import factory.Bad.pizza.PepperPizza;
import factory.Bad.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("cheese")){
                pizza = new CheesePizza();
            }else if(orderType.equals("greek")){
                pizza = new GreekPizza();
            }else if(orderType.equals("pepper")){
                pizza = new PepperPizza();
            }else { //输入异常
                break;
            }
            //开始烘烤包装
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();

        }while(true);
    }

    //输入相应的种类
    private String getType() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("input  pizza type : ");
        String str = null;
        try {
            str = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }
}

测试类:

package factory.Bad.test;

import factory.Bad.order.OrderPizza;

public class MyTest {
    public static void main(String[] args) {
        OrderPizza orderPizza = new OrderPizza();
    }
}

测试情况
这里写图片描述

  • 上面的测试方案的不好之处在于如果我们想增加新的披萨,就需要修改订单中的if esle语句,每次增加,都要修改
  • 所以对于可能以后会变化的地方,我们可以封装成另一个类,抽取出来,降低耦合度。

(2)使用简单工厂模式

这里写图片描述

我们可以把需要改变的那部分抽取出来成为一个类: (所以简单工厂模式很简单,只是把之前的可以变化的部分抽取出来)
这里写图片描述
我们看OrderPizza类和SimplePizzaFactory类,和上面的代码只有这里有变化:

package factory.SimpleFactory.factory;
import factory.SimpleFactory.pizza.CheesePizza;
import factory.SimpleFactory.pizza.GreekPizza;
import factory.SimpleFactory.pizza.PepperPizza;
import factory.SimpleFactory.pizza.Pizza;

public class SimplePizzaFactory {
    /**
     * 这个方法也可以写成 静态的,,这样在  OrderPizza类中就不需要传入这个类的对象了
     * (不过写成静态的也有不好的地方,不能通过继承来改变创建的行为)
     */
    public Pizza createPizza(String orderType){
        Pizza pizza = null;
        if(orderType.equals("cheese")){
            pizza = new CheesePizza();
        }else if(orderType.equals("greek")){
            pizza = new GreekPizza();
        }else if(orderType.equals("pepper")){
            pizza = new PepperPizza();
        }
        return pizza;
    }
}

OrderPizza类中要有SimplePizzaFactory类的对象引用

package factory.SimpleFactory.order;

import factory.SimpleFactory.factory.SimplePizzaFactory;
import factory.SimpleFactory.pizza.CheesePizza;
import factory.SimpleFactory.pizza.GreekPizza;
import factory.SimpleFactory.pizza.PepperPizza;
import factory.SimpleFactory.pizza.Pizza;

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

public class OrderPizza {

    SimplePizzaFactory simplePizzaFactory;

    public OrderPizza(SimplePizzaFactory simplePizzaFactory) {
        this.simplePizzaFactory = simplePizzaFactory;
        setFactory();
    }
    //直接在构造函数中
    public void setFactory() {
        Pizza pizza = null;
        String orderType;
        do{
            orderType = getType();
            pizza = simplePizzaFactory.createPizza(orderType);
            if (pizza != null) {
                //开始烘烤包装
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }

        }while(true);
    }

    private String getType() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("input pizza type : ");
        String str = null;
        try {
            str = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }
}

测试类

package factory.SimpleFactory.test;

import factory.SimpleFactory.factory.SimplePizzaFactory;
import factory.SimpleFactory.order.OrderPizza;

public class MyTest {
    public static void main(String[] args) {
        OrderPizza orderPizza = new OrderPizza(new SimplePizzaFactory());
    }
}

测试效果和之前是一样的。

(3)使用工厂方法模式

上面的方法可以解决耦合的问题,但是如果我们还有很多连锁披萨店,而且各个地方的披萨必须带上自己的特色,那么我们就可以使用工厂方法设计模式

这里写图片描述
这里写图片描述
先看几个有特色的披萨

package factory.FactoryMethod.pizza;
/**
 * Pizza超类
 */
public abstract class Pizza {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return 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 !");
    }
}
package factory.FactoryMethod.pizza;

public class LDCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("LDCheesePizza");
        System.out.println(getName() + "  preparing !");
    }
}
package factory.FactoryMethod.pizza;

public class LDPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("LDPepperPizza");
        System.out.println(getName() + "   preparing!");
    }
}
package factory.FactoryMethod.pizza;

public class NYCheesePizza extends Pizza{
    @Override
    public void prepare() {
        setName("NYCheesePizza");
        System.out.println(getName() + "  preparing !");
    }
}
package factory.FactoryMethod.pizza;

public class NYPepperPizza extends Pizza {
    @Override
    public void prepare() {
        setName("NYPepperPizza");
        System.out.println(getName() + "  preparing!");
    }
}

然后就是三个”工厂”,把OrderPizza设计成抽象类,然后LDOrderPizza和NYOrderPizza都继承自OrderPizza:

package factory.FactoryMethod.order;

import factory.FactoryMethod.pizza.Pizza;

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

public abstract class OrderPizza {

    public OrderPizza(){
        Pizza pizza = null;
        String orderType;
        do{
            orderType = getType();
            pizza = createPizza(orderType);
            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }
        }while(true);
    }

    //子类实现
    public abstract Pizza createPizza(String orderType);

    private String getType() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("input pizza type  : ");
        String str = null;
        try {
            str = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }
}
package factory.FactoryMethod.order;

import factory.FactoryMethod.pizza.NYCheesePizza;
import factory.FactoryMethod.pizza.NYPepperPizza;
import factory.FactoryMethod.pizza.Pizza;

public class NYOrderPizza extends OrderPizza  {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")){
            pizza = new NYCheesePizza();
        }else if(orderType.equals("pepper")){
            pizza = new NYPepperPizza();
        }
        return pizza;
    }
}
package factory.FactoryMethod.order;

import factory.FactoryMethod.pizza.LDCheesePizza;
import factory.FactoryMethod.pizza.LDPepperPizza;
import factory.FactoryMethod.pizza.Pizza;

public class LDOrderPizza extends OrderPizza {
    @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;
    }
}

测试类:

package factory.FactoryMethod.test;

import factory.FactoryMethod.order.LDOrderPizza;
import factory.FactoryMethod.order.NYOrderPizza;
import factory.FactoryMethod.order.OrderPizza;

public class MyTest {
    public static void main(String[] args) {
//        OrderPizza orderPizza = new LDOrderPizza();
        OrderPizza orderPizza = new NYOrderPizza();
    }
}

测试纽约的披萨效果
这里写图片描述

(4)使用抽象工厂模式

这里写图片描述
这里写图片描述
就是明确的指定一个抽象工厂,以及下面的子工厂,具体设计如下:
先看三个工厂

package factory.AbstractFactory.factory;

import factory.AbstractFactory.pizza.Pizza;

public interface AbsFactory {
    public Pizza createPizza(String orderType);
}
package factory.AbstractFactory.factory;

import factory.AbstractFactory.pizza.LDCheesePizza;
import factory.AbstractFactory.pizza.LDPepperPizza;
import factory.AbstractFactory.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;
    }
}
package factory.AbstractFactory.factory;

import factory.AbstractFactory.pizza.NYCheesePizza;
import factory.AbstractFactory.pizza.NYPepperPizza;
import factory.AbstractFactory.pizza.Pizza;

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

然后是点单系统: 里面有总工厂对象的引用:

package factory.AbstractFactory.order;

import factory.AbstractFactory.factory.AbsFactory;
import factory.AbstractFactory.pizza.Pizza;

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

public class OrderPizza {
    AbsFactory absFactory;

    public OrderPizza(AbsFactory absFactory) {
        this.absFactory = absFactory;
        setFactory();
    }

    private void setFactory() {
        Pizza pizza = null;
        String orderType;

        do {
            orderType = getType();
            pizza = absFactory.createPizza(orderType);
            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else {
                break;
            }

        }while (true);
    }

    private String getType() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("input pizza  type  : ");
        String str = null;
        try {
            str = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }
}

测试类:

package factory.AbstractFactory.test;

import factory.AbstractFactory.factory.LDFactory;
import factory.AbstractFactory.factory.NYFactory;
import factory.AbstractFactory.order.OrderPizza;

public class MyTest {
    public static void main(String[] args) {
//        OrderPizza orderPizza = new OrderPizza(new LDFactory());
        OrderPizza orderPizza2 = new OrderPizza(new NYFactory());
    }
}

运行效果和工厂模式一样。

工厂模式案例二

再看一个模拟鼠标,键盘,耳麦为产品,惠普,戴尔为工厂的例子。

(1)使用简单工厂模式

这里写图片描述
这里写图片描述
Mouse

package factory.practice.SimpleFactory;

public abstract class Mouse {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public abstract void display();
}
package factory.practice.SimpleFactory;

public class DellMouse extends Mouse {

    public DellMouse(){
        setName("DellMouse");
    }
    @Override
    public void display() {
        System.out.println(getName() + " ! ");
    }
}
package factory.practice.SimpleFactory;

public class HpMouse extends Mouse {

    public HpMouse() {
        setName("HpMouse");
    }

    @Override
    public void display() {
        System.out.println(getName() + " ! ");
    }
}

Mouse工厂(根据类型生成不同工厂的鼠标)

package factory.practice.SimpleFactory;

public class MouseFactory {

    public static Mouse createMouse(String type){
        if(type.equals("dell")){
            return new DellMouse();
        }else if(type.equals("hp")){
            return new HpMouse();
        }
        return null;
    }

}

测试

package factory.practice.SimpleFactory;

import java.io.BufferedInputStream;
import java.util.Scanner;

public class MyTest {

    public static void main(String[] args) {
        Scanner cin = new Scanner(new BufferedInputStream(System.in));
        String type = cin.nextLine();
        Mouse mouse = MouseFactory.createMouse(type);
        mouse.display();
    }
}

效果
这里写图片描述


(2)使用工厂模式

这里写图片描述

这里写图片描述
三个工厂

package factory.practice.FactoryMethod;

public interface MouseFactory {

    Mouse createMouse();
}
package factory.practice.FactoryMethod;

public class DellMouseFactory implements MouseFactory {
    @Override
    public Mouse createMouse() {
        return new DellMouse();
    }
}
package factory.practice.FactoryMethod;

public class HpMouseFactory implements MouseFactory {
    @Override
    public Mouse createMouse() {
        return new HpMouse();
    }
}

其他的鼠标类不变(就不重复贴了)
测试类

package factory.practice.FactoryMethod;

public class MyTest {
    public static void main(String[] args) {
        MouseFactory mouseFactory = new DellMouseFactory();
        mouseFactory.createMouse().display();
    }
}

效果

DellMouse ! 

(3)使用抽象工厂

这个是当我们在抽象工厂中添加多个方法(就是说PC厂商不仅生成鼠标,还要生产键盘),就成为了抽象工厂。

这里写图片描述
这里写图片描述
代码就不贴了放在我的github代码仓库


小结

这里写图片描述

工厂方法要多加练习,才能在实际项目中好好运用,这里还给出一个讲的好的博客

猜你喜欢

转载自blog.csdn.net/zxzxzx0119/article/details/81357402
今日推荐