java设计模式-工厂模式

devtools/2024/12/23 10:19:49/

文章目录

  • 概念
  • 一、简单工厂模式
    • 1、角色和职责
    • 2、优点
    • 3、缺点
    • 4、适用场景
    • 5、示例1
    • 6、示例2
    • 7、示例3
    • 8、示例4:枚举
    • 9、示例5:反射
  • 二、工厂方法模式
    • 1、角色和职责
    • 2、优点
    • 3、缺点
    • 4、使用场景
    • 5、示例1
  • 三、抽象工厂模式
    • 1、角色和职责
    • 2、优点
    • 3、缺点
    • 4、适用场景
    • 5、示例1

概念

Java 中的工厂模式是设计模式的一种,主要用于管理对象的创建。它帮助将对象的实例化逻辑从使用对象的逻辑中分离出来,使得代码更加模块化,增加了代码的灵活性和可维护性。工厂模式主要有三种变体:简单工厂模式、工厂方法模式和抽象工厂模式

一、简单工厂模式

简单工厂模式并不是一个真正的设计模式,但是它是工厂方法模式的一个简化版本。它有一个中心化的工厂类,负责创建其他类的实例。客户端通过传递类型信息给工厂,来获取所需的对象实例。简单工厂模式适合产品种类较少且不会频繁增加的场景,在这种情况下,可以通过简单工厂模式简化对象的创建过程,同时保持客户端和具体产品解耦。

1、角色和职责

角色

  1. 工厂类(Factory Class):这是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的职责是提供一个创建对象的方法,客户端通过调用这个方法来创建对象。这个方法通常根据传递给它的参数来决定创建哪种类型的对象。
  2. 抽象产品(Abstract Product):这是一个接口或抽象类,定义了产品的公共接口。在具体实现类中,这些接口或抽象类的方法将被实现。
  3. 具体产品(Concrete Product):继承或实现抽象产品的类,工厂类将创建并返回这些具体产品的实例。每个具体产品都会实现抽象产品定义的接口,表示不同类型的产品对象。

职责

  1. 工厂类的职责
  • 根据客户端的请求,决定创建哪种具体产品的实例。
  • 隐藏了创建产品的具体逻辑,客户端不需要知道具体产品类的名字,只需要知道工厂类。
  • 可能包含选择合适产品类并创建其实例的逻辑。
  1. 抽象产品的职责
  • 声明所有具体产品都应实现的接口,定义了产品的规范,确保所有具体产品的一致性。
  1. 抽象产品的职责
  • 实现或继承抽象产品的接口或类,定义具体产品的具体属性和方法。
  • 每个具体产品都将提供不同的实现,这些实现通过工厂类创建并返回给客户端。

2、优点

  • 帮助实现了代码的解耦,客户端不需要直接创建对象,而是通过工厂类来做这件事,减少了客户端和产品对象之间的依赖。
  • 添加新的产品类时,只需要扩展工厂类即可,无需修改已有的客户端代码,提高了系统的可维护性。

3、缺点

  • 当添加新产品时,需要修改工厂类,违反了开闭原则。
  • 工厂类的职责过重,随着产品种类的增加,工厂方法会变得越来越复杂。

4、适用场景

  • 创建的对象数量不多且不会频繁变化。
  • 客户端不关心对象的创建过程。

5、示例1

  1. 定义一个接口或者抽象类(Product):所有具体的产品实现这个接口或继承这个抽象类,这些产品在概念上是相关的,但实现细节不同。
  2. 创建具体的产品类(Concrete Products):实现或继承第一重定义接口或抽象类。每个具体产品都包含特定于产品的实现代码。
  3. 创建工厂(Factory):包含一个或多个方法,这些方法用于根据输入参数的不同,决定创建并返回哪一种具体产品的实例。客户端调用这个方法而不是直接创建产品对象。
  4. 客户端调用工厂类的方法:客户端使用工厂类,而不是直接实例化产品对象。客户端不需要知道如何创建这些对象,只需知道工厂方法的参数。
    假设我们有一个应用,需要根据用户的需求创建不同类型的日志记录器,比如文件日志记录器和数据库日志记录器。

第一步:定义产品接口

java">public interface Logger {void log(String message);
}

第二步:创建具体产品类

java">public class FileLogger implements Logger {public void log(String message) {System.out.println("Logging message to a file: " + message);}
}public class DatabaseLogger implements Logger {public void log(String message) {System.out.println("Logging message to the database: " + message);}
}

第三步:创建工厂类

java">public class LoggerFactory {public static Logger getLogger(String type) {if (type.equalsIgnoreCase("file")) {return new FileLogger();} else if (type.equalsIgnoreCase("database")) {return new DatabaseLogger();} else {throw new IllegalArgumentException("Unknown logger type");}}
}

第四步:客户端调用工厂类的方法

java">public class Client {public static void main(String[] args) {Logger logger = LoggerFactory.getLogger("file");logger.log("This is a message.");logger = LoggerFactory.getLogger("database");logger.log("This is another message.");}
}

6、示例2

步骤1:创建产品接口和具体产品类,首先定义一个产品接口FileViewer和几个具体的产品类TextViewerImageViewerVideoViewer,每个产品类实现 FileViewer接口。

java">interface FileViewer {void display();
}class TextViewer implements FileViewer {public void display(){System.out.println("Display text file...");}
}class ImageViewer implements FileViewer {public void display(){System.out.println("Display image file...");}
}class VideoViewer implements FileViewer {public void display(){System.out.println("Display video file...");}
}

步骤2:创建一个简单工厂类ViewerFactory,它有一个静态方法 createViewer,根据文件类型返回对应的视图对象。

java">class ViewerFactory {public static FileViewer createViewer(String fileType){switch(fileType){case: "text"return new TextViewer();case: "image"return new ImageViewer();case: "video"return new VideoViewer();default:throw new IllegalArgumentException("Unsupported file type:" + fileType);}}
}

步骤3:客户端使用工厂类

java">public class FactoryClient{public static void main(String[] args){FileViewer viewer = ViewerFactory.createViewer("text");viewer.display();viewer = ViewerFactory.createViewer("image");viewer.display();}
}

7、示例3

java">public interface ICar {void drive();
}public class Bmw implements ICar {public void drive(){System.out.println("Bmw");}
}public class Audi implements ICar{public void drive(){// audi}
}public class Benz implements ICar{public void drive(){// benz}
}public class SimpleFactory{private SimpleFactory(){ }public static ICar createCar(String carType){if("BMW".equalsIgnoreCase(carType)){return new Bmw();}else if ("Audi".equalsIgnoreCase(carType)){return new Audi();}else if ("Benz".equalsIgnoreCase(carType)){return new Benz();}else {return null;}}
}
java">public class FactoryClient{public static void main(String[] args){SimpleFactory.create("BMW").drive();}
}

8、示例4:枚举

java">public enum EnumCarFactory{BMW{@Overridepublic ICar create(){return new Bmw();}},AUDI{@Overridepublic ICar create(){return new Audi();}},BENZ{@Overridepublic ICar create(){return new Benz();}}// abstarct 修饰,强制每个枚举实现该方法public abstarct ICar create();
}
java">public class FactoryClient{public static void main(String[] args){EnumCarFactory.AUDI.create().drive();}
}

9、示例5:反射

java">public class EnhancedSimpleFactory{private EnhancedSimpleFactory() {}public static <T> T create(Class<? extend T> clazz){T obj = null;try {obj = (T) Class.forName(clazz.getName()).newInstance();} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e){e.printStackTrace();}return obj;}
}
java">public class FactoryClient{public static void main(String[] args){// 入参类路径也可来自配置文件、数据库等,因此更具灵活性。EnhancedSimpleFactory.create(Benz.class).drive()}
}

二、工厂方法模式

工厂方法模式是设计模式中的一种,属于创建型模式的一部分。它定义了一个创建对象的接口,但是让实现这个接口的类来决定实例化哪一个类。工厂方法让类的实例化延迟到其子类进行。

1、角色和职责

角色

  1. 抽象产品(Abstract Product):这是一个接口或抽象类,定义了产品的公共接口。所有的产品类都需要实现这个接口,这样的设计使得所有产品类在概念上是相同的。
  2. 具体产品(Concrete Product):实现或继承自抽象产品的类。每个具体产品都会定义具体的业务操作,这些是客户端所期望的功能。
  3. 抽象工厂(Creator):这是一个接口或抽象类,声明了工厂方法,这个方法返回一个抽象产品类型。抽象工厂使得创建对象的实现延迟到其子类中进行。
  4. 具体工厂(Concrete Creator):继承或实现抽象工厂的类。具体工厂负责创建一个或多个具体产品的实例,决定实例化哪个产品类。每个具体工厂都必须实现抽象工厂定义的工厂方法。

职责

  1. 抽象产品(Product)的职责
  • 定义所有具体产品必须实现的接口,确保所有产品类在概念上是一致的,提供了产品实例的通用属性和方法。
  1. 具体产品(Concrete Product)的职责
  • 实现抽象产品接口定义的操作,代表特定实现的产品对象。
  1. 抽象工厂(Creator)的职责
  • 声明工厂方法,返回一个产品实例。工厂方法通常是抽象的,需要子类实现。
  • 可以提供工厂方法的默认实现,返回一个默认的产品对象。
  1. 具体工厂(Concrete Creator)的职责
  • 重写或实现抽象工厂中定义的工厂方法,以创建和返回具体产品的实例。具体工厂知道应当实例化哪一个具体产品类。
  • 直接与客户端代码交互,提供创建产品的具体实现。

2、优点

  • 提供了代码解耦:在工厂方法模式中,客户端不需要知道它所创建实例的类的具体类名,只需知道对应的工厂即可。这有助于系统在不修改客户端代码的情况下引入新的类,提高了系统的灵活性。
  • 扩展性高:添加新的产品类不需要修改已有的工厂类,只需添加相应的具体产品类和对应的具体工厂即可,符合开闭原则。
  • 强制隔离了创建和使用代码:用户只关心产品的接口而不关心具体类的实现,工厂方法也使得用户代码和具体类的实现解耦。
  • 提供了一种扩展的策略,比简单工厂模式更有弹性。

3、缺点

  • 可能导致类的数量增加:每增加一个产品,都需要增加一个具体产品类和一个具体工厂类,这会导致系统类的数量成倍增加,增加了系统的复杂性。
  • 系统的抽象性和理解难度增加:需要引入抽象层,在客户端代码中既包含抽象也包含具体类的操作,对系统结构和抽象层的理解将会更加复杂。

4、使用场景

  • 当一个类不知道它所必须创建的对象的类的时候:在工厂方法模式中,类的实例化延迟到其子类。
  • 当一个类希望由它的子类来指定创建对象的时候:工厂方法使类的实例可以在运行时更加灵活地增加新的类型。
  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪个帮助子类是委托者这一信息局部化时

5、示例1

考虑一个日志记录器的例子,我们需要根据不同的场景(例如文件日志记录和数据库日志记录)创建不同类型的日志记录器。

步骤 1: 定义产品接口

java">public interface Logger {void log(String message);
}

步骤 2: 创建具体产品类

java">public class FileLogger implements Logger {public void log(String message) {System.out.println("File logger: " + message);}
}public class DatabaseLogger implements Logger {public void log(String message) {System.out.println("Database logger: " + message);}
}

步骤 3: 定义工厂接口

java">public interface LoggerFactory {Logger createLogger();
}

步骤 4: 创建具体工厂类

java">public class FileLoggerFactory implements LoggerFactory {public Logger createLogger() {// 可以在这里添加创建FileLogger前的逻辑,如配置加载等return new FileLogger();}
}public class DatabaseLoggerFactory implements LoggerFactory {public Logger createLogger() {// 可以在这里添加创建DatabaseLogger前的逻辑,如配置加载等return new DatabaseLogger();}
}

步骤 5: 客户端代码

java">public class FactoryMethodDemo {public static void main(String[] args) {LoggerFactory factory;Logger logger;// 使用文件日志记录器factory = new FileLoggerFactory();logger = factory.createLogger();logger.log("This is a file log message.");// 使用数据库日志记录器factory = new DatabaseLoggerFactory();logger = factory.createLogger();logger.log("This is a database log message.");}
}

这个示例中,**LoggerFactory** 是工厂接口,**FileLoggerFactory** **DatabaseLoggerFactory**是具体的工厂类,它们负责创建对应的产品类实例。客户端代码仅与接口 **LoggerFactory** **Logger** 交互,具体使用哪个日志记录器类的决定权交给了具体的工厂类,这样就实现了创建逻辑与使用逻辑的分离,提高了代码的灵活性和扩展性。

三、抽象工厂模式

抽象工厂模式是一种创建型设计模式,它提供了一种方式,可以封装一组具有共同主题的单独的工厂而无需指定它们的具体类。这种模式是围绕一个超级工厂创建其他工厂的概念。该超级工厂又称为其他工厂的工厂。在抽象工厂模式中,接口是负责创建相关对象的工厂,不需要明确指定它们的类。

1、角色和职责

角色

  1. 抽象工厂(Abstract Factory):提供一个接口,用于创建一系列相关或相互依赖的对象,而不需要指定它们具体的类。
  2. 具体工厂(Concrete Factory):实现抽象工厂接口的具体类。每个具体工厂都能够按照工厂接口定义的方式生产一组具体产品。不同的具体工厂对应于不同的产品变体。
  3. 抽象产品(Abstract Product):为一系列产品对象声明一个接口。在抽象接口中声明了所有产品必须实现的操作。
  4. 具体产品(Concrete Product)抽象工厂模式所创建的实际产品对象,每个具体产品都是一个抽象产品的实现。
  5. 客户端(Client):仅使用由抽象工厂和抽象产品提供的接口声明的方法。客户端通过抽象接口操纵实例,从而使得与应用程序的具体类解耦。

职责

  1. 抽象工厂(Abstract Factory)的职责
  • 声明了一组用于创建一系列相关或相互依赖对象的方法,每个方法对应于一种产品。
  1. 具体工厂(Concrete Factory)的职责
  • 实现抽象工厂的方法来创建具体的产品对象。每个具体工厂对应于特定的产品变体,并创建具有特定实现的产品对象。
  1. 抽象产品(Abstract Product)的职责
  • 为一类产品声明接口。在该接口中声明了所有具体产品都必须实现的操作。
  1. 具体产品(Concrete Product)的职责
  • 实现抽象产品接口的具体类。定义了一个将被相应的具体工厂创建的产品对象。
  1. 客户端(Client)的职责
  • 仅调用从抽象工厂和抽象产品类中派生的接口。客户端通过这些接口与工厂创建的对象交互,从而使具体的工厂和产品类与客户端代码解耦。

2、优点

  • 分离接口和实现:客户端代码通过接口操作实例,从而解耦了客户端和具体类的依赖。
  • 增加新的具体工厂和产品族很方便:无需修改现有系统,符合开闭原则,系统的可扩展性好。
  • 强化了程序的抽象层次抽象工厂模式通过使用产品族,能够更方便地进行替换产品系列,增加了程序的灵活性和可维护性。

3、缺点

  • 难以支持新种类的产品:如果需要添加新产品,则必须修改抽象工厂的接口,这将涉及到抽象工厂类及其所有子类的修改,违背了开闭原则。
  • 增加了系统的抽象性和复杂度:引入了多层接口和类,系统的学习和理解难度增加。

4、适用场景

  • 当系统中的产品有多于一个的产品族,而系统只消费其中某一族的产品时:抽象工厂可以为访问某一产品族的产品提供接口。
  • 当一个产品族中的多个对象被设计成一起工作时,它可以保证客户端始终只使用同一个产品族中的对象。
  • 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。

5、示例1

假设我们正在开发一个跨平台的UI库,我们需要为不同的操作系统(如Windows和Mac)创建不同风格的UI元素(如按钮和复选框)。我们将使用抽象工厂模式来解决这个问题。

步骤 1: 创建抽象产品类和具体产品类

java">public interface Button {void paint();
}public class WinButton implements Button {public void paint() {System.out.println("Render a button in Windows style");}
}public class MacButton implements Button {public void paint() {System.out.println("Render a button in MacOS style");}
}public interface Checkbox {void paint();
}public class WinCheckbox implements Checkbox {public void paint() {System.out.println("Render a checkbox in Windows style");}
}public class MacCheckbox implements Checkbox {public void paint() {System.out.println("Render a checkbox in MacOS style");}
}

步骤 2: 创建抽象工厂类和具体工厂类

java">public interface GUIFactory {Button createButton();Checkbox createCheckbox();
}public class WinFactory implements GUIFactory {public Button createButton() {return new WinButton();}public Checkbox createCheckbox() {return new WinCheckbox();}
}public class MacFactory implements GUIFactory {public Button createButton() {return new MacButton();}public Checkbox createCheckbox() {return new MacCheckbox();}
}

步骤 3: 客户端代码

java">public class Application {private Button button;private Checkbox checkbox;public Application(GUIFactory factory) {button = factory.createButton();checkbox = factory.createCheckbox();}public void paint() {button.paint();checkbox.paint();}
}public class Demo {public static void main(String[] args) {GUIFactory factory = new WinFactory();Application app = new Application(factory);app.paint();factory = new MacFactory();app = new Application(factory);app.paint();}
}

在这个例子中,GUIFactory是一个抽象工厂,负责定义创建UI元素的接口。WinFactoryMacFactory是具体的工厂,实现了GUIFactory接口,分别创建Windows风格和Mac风格的UI元素。客户端代码依赖于抽象工厂和抽象产品的接口,从而可以在不关心具体产品细节的情况下,使用不同的产品族。这就是抽象工厂模式的强大之处。


http://www.ppmy.cn/devtools/35506.html

相关文章

如何快速开发项目,提高开发效率

文章目录 一、问题描述二、问题解决1.需求分析2.架构设计3.技术选型4.正式开发 一、问题描述 有很多小伙伴在开发一个项目的时候&#xff0c;总是需要很长时间&#xff0c;效率很低&#xff0c;其实本质是没有掌握开发项目的关键和技巧 我下面列举一些问题&#xff0c;不知道…

SpringBoot整合rabbitmq使用案例

RocketMQ&#xff08;二十四&#xff09;整合SpringBoot SpringBoot整合rabbitmq使用案例 一 SpringBoot整合RocketMQ实现消息发送和接收消息生产者1&#xff09;添加依赖2&#xff09;配置文件3&#xff09;启动类4&#xff09;测试类 消息消费者1&#xff09;添加依赖2&…

【LeetCode 121】买卖股票的最佳时机

思路 思路&#xff1a; 所谓代码的复杂性来源于业务的复杂性&#xff0c;如果能够想清楚业务实现逻辑&#xff0c;就能够轻松写出代码&#xff1b; 假设当前是第i天&#xff0c;如何在第i天赚到最多的钱&#xff1f;需要在第i天之前以最低价买入股票&#xff1b; 所以需要求…

Sarcasm detection论文解析 |基于情感背景和个人表达习惯的有效讽刺检测方法

论文地址 论文地址&#xff1a;https://link.springer.com/article/10.1007/s12559-021-09832-x#/ 论文首页 笔记框架 基于情感背景和个人表达习惯的有效讽刺检测方法 &#x1f4c5;出版年份:2022 &#x1f4d6;出版期刊:Cognitive Computation &#x1f4c8;影响因子:5.4 &…

Typescript语法三

枚举 枚举&#xff08;Enumeration&#xff09;是编程语⾔中常⻅的⼀种数据类型&#xff0c;其主要功能是定义⼀组有限的选项&#xff0c;例 如&#xff0c;⽅向&#xff08;上、下、左、右&#xff09;或季节&#xff08;春、夏、秋、冬&#xff09;等概念都可以使⽤枚举类型…

从论文中看AI绘画

个人博客:Sekyoro的博客小屋 个人网站:Proanimer的个人网站 主要看是看Diffusion Models,CLIP,ControlNet,IP-Adapter这种经典论文,尝试总结论文写作的一些方式以及图像生成模型的一些内在思想. 对于其中的数学原理和代码不过深究. DDPM 使用扩散模型得到高质量图像,证明了这…

嵌入式学习day11

每日面试题 全局变量可不可以定义在可被多个.c文件包含的头文件中&#xff0c;为啥&#xff1f; 可以&#xff0c;在不同的C文件中各自用static声明的全局变量&#xff0c;变量名可能相同&#xff0c;但是各自C文件中的全局变量的作用域为该文件&#xff0c;所以互不干扰。 …

【python】条件语句与循环语句

目录 一.条件语句 1.定义 2.条件语句格式 &#xff08;1&#xff09;if &#xff08;2&#xff09;if-else &#xff08;3&#xff09;elif功能 &#xff08;4&#xff09;if嵌套使用 3.猜拳游戏 二.循环语句 1. while循环 2.while嵌套 3.for循环 4.break和conti…