Java超详细讲解设计模式之一的工厂模式

作者:〖雪月清〗 时间:2023-03-26 21:08:04 

工厂模式

在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());
   }
}

类图

Java超详细讲解设计模式之一的工厂模式

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

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

注意:

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

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

类图

Java超详细讲解设计模式之一的工厂模式

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

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();

}
}

类图

Java超详细讲解设计模式之一的工厂模式

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

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());

}

}

成功!!!

Java超详细讲解设计模式之一的工厂模式

来源:https://blog.csdn.net/qq_52595134/article/details/123715948

标签:Java,工厂模式,设计模式
0
投稿

猜你喜欢

  • Android使用CrashHandler来获取应用的crash信息的方法

    2023-07-25 20:27:38
  • 关于MyBatis结果映射的实例总结

    2022-02-21 02:31:31
  • android使用OkHttp实现下载的进度监听和断点续传

    2022-03-23 12:37:07
  • C++语言实现线性表之链表实例

    2023-06-20 22:21:20
  • 深入了解Java设计模式之策略模式

    2021-06-24 22:45:56
  • Android自定义listview布局实现上拉加载下拉刷新功能

    2023-05-12 23:27:28
  • Java集合框架ArrayList源码分析(一)

    2022-05-12 19:32:50
  • SpringBoot整合JDBC、Druid数据源的示例代码

    2022-06-19 20:44:24
  • C语言函数声明以及函数原型超详细讲解示例

    2023-03-31 03:12:02
  • java实现邮件发送

    2022-06-03 02:48:20
  • Java GUI编程实现在线聊天室

    2022-04-07 22:50:09
  • Java date format时间格式化操作示例

    2021-10-28 19:12:24
  • Mybatis步骤分解实现一个增删改查程序

    2021-09-16 01:12:43
  • Java 实战项目锤炼之医院门诊收费管理系统的实现流程

    2022-08-10 11:35:08
  • Android开发之滑动图片轮播标题焦点

    2022-07-13 11:59:15
  • C#中除去所有在HTML元素中标记

    2023-04-14 04:09:56
  • C#实现Excel导入sqlite的方法

    2021-12-02 23:38:17
  • Spring Boot集成教程之异步调用Async

    2023-03-10 03:39:50
  • java实现京东秒杀功能分享 京东秒杀软件

    2021-09-10 23:27:36
  • Android开发:浅谈MVP模式应用与内存泄漏问题解决

    2023-05-01 20:42:43
  • asp之家 软件编程 m.aspxhome.com