avatar

java工厂模式

一个小例子引入

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

  • 披萨的种类有很多(比如GreekPizz,CheesePizz等)
  • 披萨的制作有prepare,bake,cut,box
  • 完成披萨店订购功能
    设计模式之工厂模式(factory pattern)

    传统方式

    这是pizza对应的类和类图
    //将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;
    }
    }
    public class PepperPizza extends pizza {
    @Override
    public void prepare() {
    // TODO Auto-generated method stub
    System.out.println(" 给PepperPizza准备原材料 ");
    }
    }
    public class GreekPizza extends pizza{
    @Override
    public void prepare() {
    // TODO Auto-generated method stub
    System.out.println(" 给希腊披萨准备原材料 ");
    }
    }
    public class CheesePizza extends pizza {
    @Override
    public void prepare() {
    // TODO Auto-generated method stub
    System.out.println(" 给制作奶酪披萨 准备原材料 ");
    }
    }
    用于进行披萨订购
    //订单处理类
    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 "";
    }
    }
    }
    //相当于一个客户端,发出订购
    public class PizzaStore {
    public static void main(String[] args) {
    new OrderPizza();
    }
    }
    如果没有设计模式,我们采取的方案应该就会使这样的,从uml可以直观的看出来,我们如果想要再增加一种pizza,那么对整个应用的改动是很大的。
    因为OrderPizza会有很多种,这里OrderPizza相当于一个门店,不同的门店需求不同卖的东西不同会产生OrderPizza1,OrderPizza2,OrderPizza3等等,如果直接与pizza类依赖这样会非常混乱

    传统方式的优缺点

  • 优点是比较好理解,简单易操作
  • 缺点是违反了设计原则的ocp原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候尽量不修改代码,或者尽可能少的修改代码

改进思路

把创建pizza对象封装到一个类中,这样我们有新的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;
}
}

修改orderpizza类和PizzaStore类

public class OrderPizza {
//定义一个简单工厂对象
private SimpleFactory simpleFactory;
private pizza pizza = null;

//构造器
public OrderPizza(SimpleFactory simpleFactory) {
setFactory(simpleFactory);
}

private void setFactory(SimpleFactory simpleFactory) {
String orderType = ""; //用户输入的

this.simpleFactory = simpleFactory; //设置简单工厂对象

do {
orderType = getType();
pizza = this.simpleFactory.createPizza(orderType);

//输出pizza
if(pizza != null) { //订购成功
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
public class PizzaStore {
public static void main(String[] args) {
new OrderPizza(new SimpleFactory());
}
}

这样简单工厂模式就是实现了,这样的好处是做到了OrderPizza与pizza的解耦,如果我们再创建一个pizza或者再创建一个orderpizza的时候改动的只有要添加的类和工厂。
简单工厂模式也叫做静态工厂模式,我们还可以这样修改代码实现工厂模式
修改简单工厂类

public static Pizza createPizza2(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;
}

修改orderpizza类和pizzastore类

public class OrderPizza2 {

Pizza pizza = null;
String orderType = "";
// 构造器
public OrderPizza2() {

do {
orderType = getType();
pizza = SimpleFactory.createPizza2(orderType);

// 输出pizza
if (pizza != null) { // 订购成功
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 "";
}
}
}
//修改pizzaorder类
public class PizzaStore {

public static void main(String[] args) {
new OrderPizza2();
}
}

使用静态工厂更加方便。

工厂方法模式

  • 现在有一个新的需求:客户在点餐的时候可以点不同口味的披萨,比如北京的奶酪pizza,北京的胡椒pizza等等等,也就是说客户不仅仅要pizza那么简单还要要pizza的制作方式
  • 思路1:使用简单工厂模式,创建不同的产品,针对每一种可能性,这这样对以后的扩展和系统的维护都非常复杂
  • 思路2:使用工厂方法模式

基本介绍

  • 简单工厂模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐字类中具体实现
  • 工厂方法模式:定义一个创建对象的抽象方法,由字类决定要实例化的类,工厂方法模式将对象的实例化推迟到了子类

    工厂方法模式结构图

    类图

代码实现

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;
}
}
public class BJCheessPizzea extends Pizza {
@Override
public void prepare() {
setName("北京的奶酪披萨");
System.out.println("北京的奶酪披萨 准备备原材料");
}
}

public class BJPepperPizza extends Pizza {
@Override
public void prepare() {
setName("北京的胡椒披萨");
System.out.println("北京的胡椒披萨 准备备原材料");
}
}
public class LDCheessPizzea extends Pizza {
@Override
public void prepare() {
setName("伦敦的奶酪披萨");
System.out.println("伦敦的奶酪披萨 准备备原材料");
}
}
public class LDPepperPizza extends Pizza {
@Override
public void prepare() {
setName("伦敦的胡椒披萨");
System.out.println("伦敦的胡椒披萨 准备备原材料");
}
}

OrderPizza类

public abstract class OrderPizza {
//定义一个抽象方法,createPizza,让各个工厂子类自己实现
abstract Pizza createPizza(String orderType);
}
public class LDOrderPizza extends OrderPizza {
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null ;
if(orderType.equals("cheese"))
{
pizza = new LDCheessPizzea();
}
else if(orderType.equals("pepper"))
{
pizza = new LDPepperPizza();
}
return pizza;
}
}
public class BJOrderPizza extends OrderPizza {
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null ;
if(orderType.equals("cheese"))
{
pizza = new BJCheessPizzea();
}
else if(orderType.equals("pepper"))
{
pizza = new BJPepperPizza();
}
return pizza;
}
}

使用

public class PizzaStore {
public static void main(String[] args)
{
OrderPizza orderPizza = new BJOrderPizza();//获得抽象工厂
Pizza pizza = orderPizza.createPizza("cheese");//根据抽象工厂的方法得到产品
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
}

这样就实现了工厂方法模式

抽象工厂

基本介绍

  • 抽象工厂模式:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体对象
  • 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合
  • 从设计层面看,抽象工厂模式就是对简单工厂模式的改进,或者说是进一步的抽象
  • 将工厂抽象成两层,AbsFactory(抽象工厂)和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类,这样将单个的简单工厂类变成工厂簇,更利于代码的维护和扩展

    抽象工厂结构图

    类图

    抽象工厂主要对应多个产品簇来说的,抽象工厂可以实现多个产品簇之间关系

代码实现

首先我们定义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;
}
}
public class PepperPizza extends Pizza {
@Override
public void prepare() {
setName("伦敦的胡椒披萨");
System.out.println("伦敦的胡椒披萨 准备备原材料");
}
}
public class CheessPizzea extends Pizza {
@Override
public void prepare() {
setName("伦敦的奶酪披萨");
System.out.println("伦敦的奶酪披萨 准备备原材料");
}
}

创建饮料类

public abstract class Drinks {
public abstract void prepare();
public void make()
{
System.out.println("制作");
}
}
public class cola extends Drinks {
@Override
public void prepare() {
System.out.println("准备可乐原材料");
}
}
public class fruitjuice extends Drinks {
@Override
public void prepare() {
System.out.println("准备果汁原材料");
}
}

创建工厂来实例化这几个类

//一个抽象工厂模式的抽象层
public interface AbsFactory {
//让下面的工厂子类实现
public Pizza createPizza();
public Drinks CreateDrinks();
}
public class Meal1Factory implements AbsFactory {
@Override
public Pizza createPizza() {
CheessPizzea cheessPizzea = new CheessPizzea();
return cheessPizzea;
}

@Override
public Drinks CreateDrinks() {
cola c = new cola();
return c;
}
}
public class Meal2Factory implements AbsFactory{
@Override
public Pizza createPizza() {
PepperPizza pepperPizza = new PepperPizza();
return pepperPizza;
}

@Override
public Drinks CreateDrinks() {
fruitjuice f = new fruitjuice();
return f;
}
}

调用


public class orderpizza {
public static void main(String[] args)
{
AbsFactory factory = new Meal1Factory();
Drinks drinks = factory.CreateDrinks();
Pizza cheese = factory.createPizza();
drinks.make();
cheese.prepare();
}
}

关于抽象工厂的好处建议看一下大话设计模式,讲的非常透彻

小结

个人对于简单工厂,工厂方法模式,抽象工厂的理解是

  • 简单工厂主要是为了将创建对象统一起来,方便管理
  • 工厂方法模式:是对一种抽象产品进行实例化
  • 抽象工厂:是为了实例化不同种产品,将调用与实现解耦,两者之间不过多牵扯。
文章作者: zenshin
文章链接: https://zlh.giserhub.com/2020/04/09/DesignPattern/factory/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 zenshin's blog
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论