工厂模式(Factory Pattern)

工厂模式(Factory Pattern)是Java中最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。工厂模式提供了一种将对象的实例化过程封装在工厂类中的方式。通过使用工厂模式,可以将对象的创建与使用代码分离,提供一种统一的接口来创建不同类型的对象。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

介绍

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决:主要解决接口选择的问题。

何时使用:我们明确地计划不同条件下创建不同实例时。

如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。

关键代码:创建过程在其子类执行。

应用实例: 

  1. 您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。

  2. Hibernate 换数据库只需换方言和驱动就可以。

  3. java.util.Calendar, ResourceBundle and NumberFormat getInstance() 使用了工厂方法模式

  4. valueOf() 在包装类中,如Boolean, Integer 也使用了工厂方法模式

工厂设计模式的优点:

  • 面向接口编程,体现了面向对象的思想

  • 将创建对象的工作转移到了工厂类

  • 一个调用者想创建一个对象,只要知道其名称就可以了

  • 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以

  • 屏蔽产品的具体实现,调用者只关心产品的接口

缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

使用场景: 

  1. 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。

  2. 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。

  3. 设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。

注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度

工厂模式包含以下几个核心角色:

  • 抽象产品(Abstract Product):定义了产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了产品对象的共同方法

  • 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性

  • 抽象工厂(Abstract Factory):声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品

  • 具体工厂(Concrete Factory):实现了抽象工厂接口,负责实际创建具体产品的对象

实现

        我们将创建一个 Shape 接口和实现 Shape 接口的实体类。下一步是定义工厂类 ShapeFactory。FactoryPatternDemo 类使用 ShapeFactory 来获取 Shape 对象。它将向 ShapeFactory 传递信息(CIRCLE / RECTANGLE / SQUARE),以便获取它所需对象的类型。

图片

步骤一:

创建一个接口:

public interface Shape {
   void draw();
}

步骤二:

创建实现接口的实体类:
Rectangle.java

public class Rectangle implements Shape { 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

Square.java

public class Square implements Shape { 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}

Circle.java

public class Circle implements Shape { 
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

步骤三:

创建一个工厂,生成基于给定信息的实体类的对象ShapeFactory.java

public class ShapeFactory {    
   //使用 getShape 方法获取形状类型的对象
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      } else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }
      return null;
   }
}

步骤四:

使用该工厂,通过传递类型信息来获取实体类的对象FactoryPatternDemo.java

public class FactoryPatternDemo {

   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();

      //获取 Circle 的对象,并调用它的 draw 方法
      Shape shape1 = shapeFactory.getShape("CIRCLE");

      //调用 Circle 的 draw 方法
      shape1.draw();

      //获取 Rectangle 的对象,并调用它的 draw 方法
      Shape shape2 = shapeFactory.getShape("RECTANGLE");

      //调用 Rectangle 的 draw 方法
      shape2.draw();

      //获取 Square 的对象,并调用它的 draw 方法
      Shape shape3 = shapeFactory.getShape("SQUARE");

      //调用 Square 的 draw 方法
      shape3.draw();
   }
}

输出结果:

Inside Circle::draw() method.Inside Rectangle::draw() method.Inside Square::draw() method.

上述是通过接口的方式进行演示工厂模式的,也叫做简单工厂模式。

如果将其ShapeFactory.java中的public Shape getShape(String shapeType)方法添加static修饰符的话,如下代码

public class ShapeFactory {
    //使用 getShape 方法获取形状类型的对象
    public static Shape getShape(String shapeType){
        if(shapeType == null){
            return null;
        }
        if(shapeType.equalsIgnoreCase("CIRCLE")){
            return new Circle();
        } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
            return new Rectangle();
        } else if(shapeType.equalsIgnoreCase("SQUARE")){
            return new Square();
        }
        return null;
    }
}

改造FactoryPatternDemo.java的main为代码如下:

...
    public static void main(String[] args) {
        //获取 Circle 的对象,并调用它的 draw 方法
        Shape shape1 = ShapeFactory.getShape("CIRCLE");
        //调用 Circle 的 draw 方法
        shape1.draw();
        //获取 Rectangle 的对象,并调用它的 draw 方法
        Shape shape2 = ShapeFactory.getShape("RECTANGLE");
        //调用 Rectangle 的 draw 方法
        shape2.draw();
        //获取 Square 的对象,并调用它的 draw 方法
        Shape shape3 = ShapeFactory.getShape("SQUARE");
        //调用 Square 的 draw 方法
        shape3.draw();
    }
...

输出结果是一样的,上述是通过接口的方式进行演示工厂模式的,也叫做静态工厂模式。


工厂模式之工厂方法模式
话不多说直接上代码:

步骤一:

创建ShapeFactory.java

public interface ShapeFactory {
    Shape draw();
}

分别创建CircleFactory.java、RectangleFactory.java、SquareFactory.java。代码分别如下:

public class CircleFactory implements ShapeFactory {
    @Override
    public Shape draw() {
        return new Circle();
    }
}

public class RectangleFactory implements ShapeFactory {
    @Override
    public Shape draw() {
        return new Rectangle();
    }
}

public class SquareFactory implements ShapeFactory {
    @Override
    public Shape draw() {
        return new Square();
    }
}

改造FactoryPatternDemo.java的main为代码如下:

...
    public static void main(String[] args) {
        //获取 CircleFactory 的对象,并调用它的 draw 方法
        Shape shape1 = new CircleFactory().draw();
        //调用 Circle 的 draw 方法
        shape1.draw();
        //获取 RectangleFactory 的对象,并调用它的 draw 方法
        Shape shape2 = new RectangleFactory().draw();
        //调用 Rectangle 的 draw 方法
        shape2.draw();
        //获取 SquareFactory 的对象,并调用它的 draw 方法
        Shape shape3 = new SquareFactory().draw();
        //调用 Square 的 draw 方法
        shape3.draw();
    }
...
输出结果:
Inside Circle::draw() method.Inside Rectangle::draw() method.Inside Square::draw() method.

这里需要注意:

      工厂方法模式解决简单工厂模式是需要付出代价的,每新增一个Shape就需要增加,对应新的工厂,会发现需要花费很大的成本,现在才三个新的Shape,那么等到十个、一百个的时候就会变得更加的复杂和难以维护。

      工厂方法模式这里还有一个点:看上面工厂方法的消费者代码示例里用到new是我们耦合的最大元凶,可以看看这篇文章里写的,利用反射对工厂模式的解耦操作;

Java高级特性——通过反射获取类的几种方式——并利用反射对工厂模式解耦操作

https://blog.csdn.net/A_hxy/article/details/105992426


总结:
第一、二个工厂模式:在实际去开发中会发现比较常用,尽管上面讲了不符合(面向对象)OOP原则。
第三个工厂方法模式:不修改工厂类的前提,也就是说不修改已有类,实现对扩展是开发,对修改关闭。

注:本文内容主要参考了 

菜鸟教程之设计模式章节

https://www.runoob.com/design-pattern/factory-pattern.html

Java设计模式:工厂模式——图文+代码示例(通俗易懂)

https://blog.csdn.net/A_hxy/article/details/105758657

技术不分好坏,合适的地方使用合适的技术;优雅的代码,清晰的逻辑,给你的每一个项目更好的归宿。

工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式,而不必暴露对象创建的逻辑。该模式定义了一个工厂类,它负责创建对象,并将其封装在一个方法中。 在.NET中,工厂模式通常使用静态方法或单例实现,其目的是创建一个对象,而无需揭示创建过程的内部细节。这种方法可以提高代码的可维护性和可复用性,并降低耦合度。 下面是一个简单的工厂模式示例,用于创建不同类型的动物: ```csharp public interface IAnimal { void Speak(); } public class Dog : IAnimal { public void Speak() { Console.WriteLine("Woof!"); } } public class Cat : IAnimal { public void Speak() { Console.WriteLine("Meow!"); } } public class AnimalFactory { public static IAnimal CreateAnimal(string type) { switch (type.ToLower()) { case "dog": return new Dog(); case "cat": return new Cat(); default: throw new ArgumentException("Invalid animal type"); } } } ``` 在上面的示例中,我们首先定义了一个IAnimal接口,它包含了Speak方法。然后,我们定义了两个具体的动物类Dog和Cat,它们实现了IAnimal接口。 最后,我们定义了一个AnimalFactory工厂类,它包含了一个静态方法CreateAnimal。该方法接受一个字符串参数,用于指定要创建的动物类型。根据给定的类型,工厂将创建相应的动物对象并返回。 使用工厂模式,我们可以轻松地创建不同类型的动物对象,而无需为每个对象创建单独的构造函数。此外,我们还可以轻松地添加新的动物类型,而无需修改现有代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值