一篇文章带你读懂设计模式之工厂模式

步入正题之前可先预习一下之前有讲过的

设计模式七大原则

单例模式



假设有这么一个场景

有一个Pizza店 需要制作Pizza,首先要考虑这几种情况

  • 制作Pizza的步骤:选择食材,制作过程(蒸烤、切片、打包)

常规思路下我们会怎么做呢?

  • 首先肯定会写一个抽象类,将Pizza制作方法抽象出来,假设其他步骤都一样((蒸烤、切片、打包),那么就需要将选材这个方法进行抽象。

  • 其次我们需要制作什么Pizza就直接继承这个抽象类,不同的Pizza实现不同的选

  • 最后准备一个Pizza店或者订单,来判断需要什么pizza,然后进行制作

传统代码实现如下:

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

不同种类Pizza实现:

public class PepperPizza extends Pizza {

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

}

Pizza订单/需求代码

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

}

客户需求/需要什么要的Pizaa(相当于Client)

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

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

}

通过以上代码可以得出结论:

如果新增了Pizza种类后,那么就需要继承Pizza抽象类;并且订单的代码还需要修改(增加if、else),而且如果其他地方也有使用的话,也会需要修改,影响使用。

并且违反了设计模式的OCP原则,即对扩展开放,对修改关闭

那么如何解决这种方式的弊端呢?

思路:

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


简单工厂模式

又称:静态工厂

概念:

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

简单模式中,定义了一个创建对象的类,由这个类来封装实例化对象的行为。

当我们用到大量创建某种、某类或者某对象时就会使用到工厂模式。

UML类图:

一篇文章带你读懂设计模式之工厂模式

如图所示:

我们在需要订购Pizza,直接去找工厂类(SimpleFactory),让SimpleFactory去完成生产Pizza的任务。这样再有新的Pizza直接修改SimpleFactory就可以,不需要改动 订单代码

代码改动:

只需要增加SimpleFactory 让订单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;
 }
 
 //简单工厂模式 也叫 静态工厂模式 
 public static Pizza createPizza2(String orderType) {

  Pizza pizza = null;

  System.out.println("使用简单工厂模式2");
  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代码修改:

这里 与SimpleFactory 采用的是聚合关系,从外部传进来的


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);
   
   //输出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 "";
  }
 }

}

OrderPizza2的修改:

简单工厂模式 也叫 静态工厂模式

所以这个类(OrderPizza2)主要是针对方法2(createPizza2)去进行修改

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




测试:

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

 public static void main(String[] args) {
  // TODO Auto-generated method stub
  //new OrderPizza();
  
  //使用简单工厂模式
  //new OrderPizza(new SimpleFactory());
  //System.out.println("~~退出程序~~");
  //使用静态工厂模式
  new OrderPizza2();
 }

}


好了简单工厂模式(静态工厂)就讲到这里了


工厂方法模式

新需求:

假设Pizza有不同口味的,比如:有北京奶酪Pizza 北京的胡椒Pizza;或者是伦敦的奶酪Pizza 伦敦的胡椒Pizza

思路1:

使用简单工厂模式,创建不同的工厂类,比如BJPizzaSimplieFactory、LONDONPizzaSimpleFactory等等,但是这样的话,可用性 可扩展性和可维护性不是特别好,以及项目的规模这都是需要考虑的因素。

思路2:

使用工厂方法模式

介绍:

将pizza项目的实例化功能抽象成抽象方法,在不同的

什么是工厂方法模式?

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

UML图:

一篇文章带你读懂设计模式之工厂模式

根据新需求代码如下

Pizza抽象类:同上

BJCheesePizza:

public class BJCheesePizza extends Pizza {

 @Override
 public void prepare() {
  // TODO Auto-generated method stub
  setName("北京的奶酪pizza");
  System.out.println(" 北京的奶酪pizza 准备原材料");
 }

}

BJPepperPizza:

public class BJPepperPizza extends Pizza {
 @Override
 public void prepare() {
  // TODO Auto-generated method stub
  setName("北京的胡椒pizza");
  System.out.println(" 北京的胡椒pizza 准备原材料");
 }
}

LDCheesePizza:

public class LDCheesePizza extends Pizza{

 @Override
 public void prepare() {
  // TODO Auto-generated method stub
  setName("伦敦的奶酪pizza");
  System.out.println(" 伦敦的奶酪pizza 准备原材料");
 }
}

LDPepperPizza:


public class LDPepperPizza extends Pizza{
 @Override
 public void prepare() {
  // TODO Auto-generated method stub
  setName("伦敦的胡椒pizza");
  System.out.println(" 伦敦的胡椒pizza 准备原材料");
 }
}

OrderPizza:


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

}

BJOrderPizza

继承OrderPizza,将创建Pizza下沉到子类BJOrderPizza,看子类和谁关联:

是OrderPizza的具体实现


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

}

LDOrderPizza

继承OrderPizza,将创建Pizza下沉到子类LDOrderPizza,看子类和谁关联:

是OrderPizza的具体实现


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

}

测试:

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
 }

}

好了工厂方法模式到这里就结束了  你了解了吗 ?接下来看一看抽象工厂模式吧


抽象工厂模式

UML类图:

一篇文章带你读懂设计模式之工厂模式

概念:

定义一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类

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

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

代码实现:

💡之前的BJCheesePizza、BJPepperPizza、LDCheesePizza、LDPepperPizza、Pizza抽象类都是之前的


我们先来完成AbsFactory 抽象工厂接口

AbsFactory :

//一个抽象工厂模式的抽象层(接口)
public interface AbsFactory {
 //让下面的工厂子类来 具体实现
 public Pizza createPizza(String orderType);
}

再来创建两个工厂子类

BJFactory:

实现AbsFactory   工厂子类

//这是工厂子类
public class BJFactory implements AbsFactory {
 @Override
 public Pizza createPizza(String orderType) {
  System.out.println("~使用的是抽象工厂模式~");
  // TODO Auto-generated method stub
  Pizza pizza = null;
  if(orderType.equals("cheese")) {
   pizza = new BJCheesePizza();
  } else if (orderType.equals("pepper")){
   pizza = new BJPepperPizza();
  }
  return pizza;
 }

}

LDFactory

实现AbsFactory 工厂子类

public class LDFactory implements AbsFactory {
 @Override
 public Pizza createPizza(String orderType) {
  System.out.println("~使用的是抽象工厂模式~");
  Pizza pizza = null;
  if (orderType.equals("cheese")) {
   pizza = new LDCheesePizza();
  } else if (orderType.equals("pepper")) {
   pizza = new LDPepperPizza();
  }
  return pizza;
 }

}

OrderPizza:

和之前的OrderPizza没有太大区别

会聚合一个AbsFactory 抽象工厂类 通过set()方法进行设置 具体是哪个工厂的子类


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

测试

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

小结:

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

设计模式的依赖抽象原则

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

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

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


以上就是设计模式中的工厂模式的全部讲解了。你学会了了吗?关注我后续带你解析更多的设计模式



原文始发于微信公众号(码上遇见你):一篇文章带你读懂设计模式之工厂模式

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/79048.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!