【Java设计模式】——工厂模式

【Java设计模式】——工厂模式在 Java 应用程序中对象无处不在 这些对象都需要进行创建 如果创建的时候直接 new 对象 那么如果我们要更换对象 所有 new 对象的地方都需要进行更改 违背了软件设计原则中的开闭原则 如果我们使用工厂生产对象 只需要在工厂中关注对象的改变即可 达到了与对象解耦的目的 工厂模式最大的特点就是解耦合 本文将介绍工厂模式的四种实现方式

???工厂模式

在Java应用程序中对象无处不在,这些对象都需要进行创建,如果创建的时候直接new对象,那么如果我们要更换对象,所有new对象的地方都需要进行更改。违背了软件设计原则中的开闭原则。如果我们使用工厂生产对象,只需要在工厂中关注对象的改变即可,达到了与对象解耦的目的,工厂模式最大的特点就是解耦合

补充:

开闭原则: 对扩展开放,对修改关闭。在程序需要进行扩展的时候,不能去修改原有的代码,实现一个热插拔的效果。是为了使程序的扩展性好,易于维护和升级。

? 1.简单工厂

?1.1结构

  • 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品: 实现或者继承抽象产品的子类
  • 具体工厂: 提供了创建产品的方法,调用者通过该方法来创建产品。

?1.2实现

以点咖啡为例:

咖啡抽象类

public abstract class Coffee { 
    / * 获取咖啡类型 * @return */ public abstract String getName(); / *加糖 */ public void addSugar(){ 
    System.out.println("加糖"); } / *加奶 */ public void addMilk(){ 
    System.out.println("加奶"); } } 

美式咖啡类

public class AmericanCoffee extends Coffee{ 
    @Override public String getName(){ 
    return "美式咖啡"; } } 

拿铁咖啡类

public class LatteCoffee extends Coffee { 
    @Override public String getName(){ 
    return "拿铁咖啡"; } } 

咖啡工厂类

public class CoffeeFactory { 
    public Coffee createCoffee(String type){ 
    Coffee coffee = null; if("american".equals(type)){ 
    coffee = new AmericanCoffee(); }else if("latten".equals(type)){ 
    coffee = new LatteCoffee(); }else{ 
    throw new RuntimeException("没有此类型的咖啡"); } return coffee; } } 

咖啡店类

public class CoffeeStore { 
    public Coffee orderCoffee(String type){ 
    CoffeeFactory factory = new CoffeeFactory(); //调用生产咖啡的方法 Coffee coffee = factory.createCoffee(type); coffee.addMilk(); coffee.addSugar(); return coffee; } } 

测试类

public class Test { 
    public static void main(String[] args) { 
    CoffeeStore coffeeStore = new CoffeeStore(); Coffee coffee = coffeeStore.orderCoffee("latten"); System.out.println(coffee.getName()); } } 

类图
image-20220324100400375

咖啡工厂负责生产咖啡(具体工厂),咖啡店通过咖啡工厂选取咖啡

其实简单工厂是大家在实际写代码的时候经常用到的,虽然简单工厂实现了咖啡店与咖啡的耦合,但是可以明显看到咖啡与咖啡工厂又耦合起来了,后期如果增加咖啡的新品种,我们需要修改咖啡工厂的代码,这又违背了“开闭原则”

注意:

简单工厂和不使用工厂是有很大区别的,如果咖啡店有多个,不使用工厂如果遇到新增咖啡需要修改所有咖啡店,但是使用工厂只需要修改咖啡工厂,类似于将所有咖啡店抽取出一个抽象的咖啡店。

?1.3优缺点

优点:

封装了创建对象的过程,可以通过参数直接获取对象,把对象的创建和业务逻辑层分开,这样可以避免之后修改客户代码,如果需要实现新产品直接修改工厂类,更容易扩展

缺点:

增加新产品时还需要修改工厂类的代码,违背了“开闭原则”

?1.4扩展

静态工厂,将工厂类中创建对象的功能定义为静态的,这样不需要再创建工厂类,直接通过类名调用静态方法,类似于工具类

public class CoffeeFactory { 
    //静态方法 public static Coffee createCoffee(String type){ 
    Coffee coffee = null; if("american".equals(type)){ 
    coffee = new AmericanCoffee(); }else if("latten".equals(type)){ 
    coffee = new LatteCoffee(); }else{ 
    throw new RuntimeException("没有此类型的咖啡"); } return coffee; } } 

?2.工厂方法

对工厂进行抽象,每一种产品对应一个具体工厂,新增产品只需要再新增对应的具体工厂,符合”开闭原则“

?2.1结构

  • 抽象工厂: 提供创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品
  • 具体工厂: 主要是实现抽象工厂中的抽象方法,完成具体产品的创建
  • 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能
  • 具体产品: 实现抽象产品所定义的接口,由具体工厂来创建,与具体工厂之间一一对应

?2.2实现

抽象咖啡类和具体咖啡类不变

咖啡工厂(抽象工厂)

public interface CoffeeFactory { 
     / * 创建咖啡 * @return */ Coffee createCoffee(); } 

美式咖啡工厂(具体工厂)

public class AmericanCoffeeFactory implements CoffeeFactory{ 
     //美式咖啡工厂对象,专门生产美式咖啡 @Override public Coffee createCoffee() { 
     return new AmericanCoffee(); } } 

拿铁咖啡工厂(具体工厂)

public class LatteCoffeeFactory implements CoffeeFactory{ 
     //拿铁咖啡工厂对象,专门生产拿铁咖啡 @Override public Coffee createCoffee() { 
     return new LatteCoffee(); } } 

咖啡店

public class CoffeeStore { 
     private CoffeeFactory factory; public void setFactory(CoffeeFactory factory) { 
     this.factory = factory; } / * 点咖啡 */ public Coffee orderCoffee() { 
     Coffee coffee = factory.createCoffee(); coffee.addSugar(); coffee.addMilk(); return coffee; } } 

测试类

public class Test { 
     public static void main(String[] args) { 
     //创建咖啡店对象 CoffeeStore coffeeStore = new CoffeeStore(); //创建工厂对象 CoffeeFactory factory = new AmericanCoffeeFactory(); coffeeStore.setFactory(factory); //点咖啡 Coffee coffee = coffeeStore.orderCoffee(); System.out.println(coffee.getName()); } } 

类图

image-20220324105512679

我们只需要知道所点咖啡具体对应的工厂对象,通过咖啡店调用对应的工厂,由工厂创建咖啡对象实现点咖啡的过程

?2.3优缺点

优点:

  • 用户只需要知道具体工厂就可以获得所需产品,无需知道产品的具体创建过程
  • 在系统新增产品时只需要添加具体产品类和对应的具体工厂类,无需对原工厂进行修改符合“开闭原则”

缺点:

每增加一个产品就要增加一个对应的具体工厂类,增加的系统的复杂性。如果具体产品种类过多,那么大量的工厂类不仅难以管理,而且也会造成程序中创建的对象过多,严重影响内存性能

?3.抽象工厂

?3.1结构

  • 抽象工厂: 提供创建产品的接口,包含多个创建产品的方法,可以创建多个不同等级的产品
  • 具体工厂: 主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建
  • 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品
  • 具体产品: 实现抽象产品所定义的接口,由具体工厂来创建,与具体工厂是多对一关系

?3.2实现

咖啡抽象类

public abstract class Coffee { 
     / * 获取咖啡类型 * @return */ public abstract String getName(); / *加糖 */ public void addSugar(){ 
     System.out.println("加糖"); } / *加奶 */ public void addMilk(){ 
     System.out.println("加奶"); } } 

美式咖啡类

public class AmericanCoffee extends Coffee{ 
     @Override public String getName(){ 
     return "美式咖啡"; } } 

拿铁咖啡类

public class LatteCoffee extends Coffee { 
     @Override public String getName(){ 
     return "拿铁咖啡"; } } 

甜品抽象类

public abstract class Dessert { 
     //甜品抽象类 public abstract void show(); } 

抹茶慕斯类

public class MatchaMousse extends Dessert{ 
     //抹茶慕斯类 @Override public void show() { 
     System.out.println("抹茶慕斯"); } } 

提拉米苏类

public class Tiramisu extends Dessert{ 
     //提拉米苏类 @Override public void show() { 
     System.out.println("提拉米苏"); } } 

甜品工厂

public interface DessertFactory { 
     / * 生产咖啡 * @return */ Coffee createCoffee(); / * 生产甜品 * @return */ Dessert createDessert(); } 

美式风味甜品工厂类

public class AmericanDessertFactory implements DessertFactory{ 
     / *美式风味甜品工厂 * 可以生产美式咖啡和抹茶慕斯 */ @Override public Coffee createCoffee() { 
     return new AmericanCoffee(); } @Override public Dessert createDessert() { 
     return new MatchaMousse(); } } 

意大利风味甜品工厂类

public class ItalyDessertFactory implements DessertFactory { 
     / *意大利风味甜品工厂 * 可以生产拿铁咖啡和提拉米苏 */ @Override public Coffee createCoffee() { 
     return new LatteCoffee(); } @Override public Dessert createDessert() { 
     return new Tiramisu(); } } 

测试类

public class Test { 
     public static void main(String[] args) { 
     //ItalyDessertFactory factory = new ItalyDessertFactory(); AmericanDessertFactory factory = new AmericanDessertFactory(); Coffee coffee = factory.createCoffee() Dessert dessert = factory.createDessert(); System.out.println(coffee.getName()); dessert.show(); } } 

类图

image-20220324150744271

由类图可见,抽象工厂不再是一个具体工厂对应一个产品,而是一个具体工厂对应一个产品族。如果需要增加一个产品族只需加对应的工厂类,符合”开闭原则“

?3.3优缺点

优点:

在工厂方法的基础上减少了部分对象的创建,适合于每次只使用同一产品族的对象这类应用场景

缺点:

当产品族中需要增加一个产品时,所有工厂都要修改


?4.模式扩展

配置文件+简单工厂

通过工厂模式+配置文件的方式解除工厂对象和产品对象的耦合。在工厂类中加载配置文件的全类名,通过反射创建对象并存储在容器中,如果需要直接从容器中获取(Spring IOC原理)

?4.1实现

1.定义配置文件

american = com.xue.config_factory.AmericanCoffee latten = com.xue.config_factory.LatteCoffee 

2.改进工厂类

public class CoffeeFactory { 
      / * 加载配置文件,获取配置文件中配置的全类名,并创建该类的对象进行存储 */ //1.定义容器对象存储咖啡对象 private static HashMap<String, Coffee> map = new HashMap<>(); //2.加载配置文件 static { 
      //创建 Properties对象 Properties properties = new Properties(); //调用properties对象中的load方法进行配置文件的加载 InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties"); try { 
      properties.load(is); //从properties中获取全类名 Set<Object> keys = properties.keySet(); for (Object key : keys) { 
      String className = properties.getProperty((String) key); //通过反射创建对象 Class class1 = Class.forName(className); Coffee coffee = (Coffee) class1.newInstance(); //将名称和对象存储在容器中 map.put((String) key,coffee); } } catch (Exception e) { 
      e.printStackTrace(); } } //根据名称获取对象 public static Coffee createCoffee(String name) { 
      return map.get(name); } } 

静态成员变量用来存储创建的对象(键存储的是名称,值存储的是对应的对象),而读取配置文件和创建对象写在静态代码块中只需要执行一次

测试类

public class Test { 
      public static void main(String[] args) { 
      Coffee coffee = CoffeeFactory.createCoffee("american"); System.out.println(coffee.getName()); System.out.println("------------"); Coffee latten = CoffeeFactory.createCoffee("latten"); System.out.println(latten.getName()); } } 

成功!!!
image-20220324165336860


以上就是Java设计模式——工厂模式的介绍及四种实现方式
往期链接:单例模式
如果大家喜欢这篇文章,可以?点赞、⭐收藏、?评论,三连支持~ ❤️❤️❤️❤️
文章参考: IT黑马Java设计模式


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

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/231387.html原文链接:https://javaforall.net

(0)
上一篇 2026年1月14日 上午9:01
下一篇 2026年1月14日 上午9:22


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号