原创 悟 老汉聊技术 2023-04-16 00:00 发表于四川
工厂模式是一种常用的创建型设计模式,它通过一个共同的接口来创建一些相关或相互依赖的对象,而无需指定其具体的类。
一、工厂模式分类
工厂模式主要分为以下几种:
-
简单工厂模式:由一个工厂类根据传入的参数,决定创建哪种产品类的实例。
-
工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪个类。使一个类的实例化延迟到其子类。
-
抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
二、工厂模式详解
下面分别详细讲解每一种工厂模式,并结合实际应用场景举例,给出示例代码。
-
简单工厂模式
简单工厂模式又叫静态工厂方法模式,它属于类创建型模式。简单工厂模式是由一个工厂类根据传入的参数,动态决定创建哪种产品类的实例。简单工厂模式适用于工厂类负责创建的对象比较少的场景。
应用场景:
假设一个系统需要记录不同种类的日志信息,例如文件日志、数据库日志、控制台日志等。系统需要提供一个可以按照用户要求创建不同种类日志的工厂类。
示例代码:
首先定义一个日志接口ILog,它包含一个写日志的方法writeLog():
public interface ILog {void writeLog();}
然后定义三个具体的日志类:FileLog、DatabaseLog和ConsoleLog:
public class FileLog implements ILog {public void writeLog() {System.out.println("记录文件日志...");}}public class DatabaseLog implements ILog {public void writeLog() {System.out.println("记录数据库日志...");}}public class ConsoleLog implements ILog {public void writeLog() {System.out.println("记录控制台日志...");}}
最后,定义一个简单工厂类,根据传入的参数创建不同种类的日志对象:
public class LoggerFactory {public static ILog createLogger(String type) {if ("file".equals(type)) {return new FileLog();} else if ("database".equals(type)) {return new DatabaseLog();} else if ("console".equals(type)) {return new ConsoleLog();} else {throw new IllegalArgumentException("unsupported type: " + type);}}}
使用时,可以通过传入不同的参数来创建不同种类的日志对象:
public class Main {public static void main(String[] args) {ILog log = LoggerFactory.createLogger("file");log.writeLog();}}
-
工厂方法模式
工厂方法模式是一种常见的创建型设计模式,它定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法模式使一个类的实例化延迟到其子类。
应用场景:
假设一个系统需要记录不同种类的日志信息,例如文件日志、数据库日志、控制台日志等。系统需要提供一个可以按照用户要求创建不同种类日志的工厂接口,并让具体工厂类去实现不同种类的日志对象创建。
示例代码:
首先定义一个日志接口ILog,它包含一个写日志的方法writeLog():
public interface ILog {void writeLog();}
然后定义三个具体的日志类:FileLog、DatabaseLog和ConsoleLog:
public class FileLog implements ILog {public void writeLog() {System.out.println("记录文件日志...");}}public class DatabaseLog implements ILog {public void writeLog() {System.out.println("记录数据库日志...");}}public class ConsoleLog implements ILog {public void writeLog() {System.out.println("记录控制台日志...");}}
接下来定义一个日志工厂接口ILoggerFactory,它包含一个创建日志对象的工厂方法createLogger():
public interface ILoggerFactory {ILog createLogger();}
然后定义三个具体的日志工厂类:FileLoggerFactory、DatabaseLoggerFactory和ConsoleLoggerFactory,分别用于创建FileLog、DatabaseLog和ConsoleLog对象:
public class FileLoggerFactory implements ILoggerFactory {public ILog createLogger() {return new FileLog();}}public class DatabaseLoggerFactory implements ILoggerFactory {public ILog createLogger() {return new DatabaseLog();}}public class ConsoleLoggerFactory implements ILoggerFactory {public ILog createLogger() {return new ConsoleLog();}}
使用时,可以通过不同的具体工厂类创建不同种类的日志对象:
public class Main {public static void main(String[] args) {ILoggerFactory factory = new FileLoggerFactory();ILog log = factory.createLogger();log.writeLog();}}
-
抽象工厂模式
抽象工厂模式是一种常用的创建型设计模式,它提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。抽象工厂模式适用于需要创建一组相关或相互依赖的对象时,可以通过一个工厂接口来实现。
应用场景:
假设一个系统需要提供一个图形界面库,其中包含不同种类的界面元素,例如按钮、文本框、复选框等。每种元素又分为不同的主题风格,例如 Windows 风格、Mac 风格、Linux 风格等。系统需要提供一个抽象工厂来创建不同种类的界面元素,使得这些元素能够和主题风格相对应。
示例代码:
首先定义抽象产品接口IButton、ITextField和ICheckBox,它们都包含一个显示的方法display():
public interface IButton {void display();}public interface ITextField {void display();}public interface ICheckBox {void display();}
然后定义三种主题风格下的具体产品类:WindowsButton、WindowsTextField、WindowsCheckBox、MacButton、MacTextField、MacCheckBox、LinuxButton、LinuxTextField和LinuxCheckBox:
public class WindowsButton implements IButton {public void display() {System.out.println("显示Windows风格按钮...");}}public class WindowsTextField implements ITextField {public void display() {System.out.println("显示Windows风格文本框...");}}public class WindowsCheckBox implements ICheckBox {public void display() {System.out.println("显示Windows风格复选框...");}}public class MacButton implements IButton {public void display() {System.out.println("显示Mac风格按钮...");}}public class MacTextField implements ITextField {public void display() {System.out.println("显示Mac风格文本框...");}}public class MacCheckBox implements ICheckBox {public void display() {System.out.println("显示Mac风格复选框...");}}public class LinuxButton implements IButton {public void display() {System.out.println("显示Linux风格按钮...");}}public class LinuxTextField implements ITextField {public void display() {System.out.println("显示Linux风格文本框...");}}public class LinuxCheckBox implements ICheckBox {public void display() {System.out.println("显示Linux风格复选框...");}}
接下来定义一个抽象工厂接口IGUIFactory,它包含三个工厂方法:createButton()、createTextField()和createCheckBox(),用于创建不同主题风格下的按钮、文本框和复选框对象:
public interface IGUIFactory {IButton createButton();ITextField createTextField();ICheckBox createCheckBox();}
然后定义三个具体的主题风格工厂类:WindowsGUIFactory、MacGUIFactory和LinuxGUIFactory,分别用于创建Windows风格、Mac风格和Linux风格下的按钮、文本框和复选框对象:
public class WindowsGUIFactory implements IGUIFactory {public IButton createButton() {return new WindowsButton();}public ITextField createTextField() {return new WindowsTextField();}public ICheckBox createCheckBox() {return new WindowsCheckBox();}}public class MacGUIFactory implements IGUIFactory {public IButton createButton() {return new MacButton();}public ITextField createTextField() {return new MacTextField();}public ICheckBox createCheckBox() {return new MacCheckBox();}}public class LinuxGUIFactory implements IGUIFactory {public IButton createButton() {return new LinuxButton();}public ITextField createTextField() {return new LinuxTextField();}public ICheckBox createCheckBox() {return new LinuxCheckBox();}}
使用时,可以通过不同的具体工厂类创建不同主题风格下的界面元素对象:
public class Main {public static void main(String[] args) {IGUIFactory factory = new WindowsGUIFactory();IButton button = factory.createButton();ITextField textField = factory.createTextField();ICheckBox checkBox = factory.createCheckBox();button.display();textField.display();checkBox.display();factory = new MacGUIFactory();button = factory.createButton();textField = factory.createTextField();checkBox = factory.createCheckBox();button.display();textField.display();checkBox.display();factory = new LinuxGUIFactory();button = factory.createButton();textField = factory.createTextField();checkBox = factory.createCheckBox();button.display();textField.display();checkBox.display();}}
上面的代码中,我们先创建了一个WindowsGUIFactory工厂对象,然后通过它分别创建了一个Windows风格的按钮、文本框和复选框,并调用了它们的display()方法进行显示。接着,我们又创建了一个MacGUIFactory工厂对象,通过它创建了一个Mac风格的按钮、文本框和复选框,并调用了它们的display()方法进行显示。最后,我们又创建了一个LinuxGUIFactory工厂对象,通过它创建了一个Linux风格的按钮、文本框和复选框,并调用了它们的display()方法进行显示。
在这个例子中,我们使用了工厂方法模式的一种变体:抽象工厂模式。它与简单工厂模式、工厂方法模式的区别在于,它不仅可以创建一个对象,而是可以创建一组相关或相互依赖的对象。在这个例子中,每个具体的GUI工厂类都可以创建一组相互依赖的界面元素对象,例如WindowsGUIFactory创建的是Windows风格的按钮、文本框和复选框对象。
抽象工厂模式通常适用于以下情况:
-
系统需要一组相关或相互依赖的对象,并且这些对象的创建过程需要统一管理。
-
系统不应依赖于产品类实例如何被创建、组合和表达的细节,这些细节应该被封装在一个共同的接口中。
-
系统中有多个产品族,而每次只使用其中某一族产品。例如本例中,我们创建了Windows、Mac和Linux三个产品族,但每次只使用其中的一个。
抽象工厂模式的优点包括:
-
抽象工厂模式将具体产品的类名封装起来,使得客户端不需要知道它们的实现细节,只需要知道它们的共同接口即可。
-
抽象工厂模式使得客户端不依赖于具体产品类,而是依赖于抽象工厂接口和抽象产品接口,这样可以在不修改客户端代码的情况下改变具体工厂类和产品类。
接下来,我们来看一个更加实际的例子,使用抽象工厂模式创建一个跨平台的UI组件库。
假设我们要创建一个UI组件库,其中包括按钮、文本框和标签等常见的组件,我们希望它可以在Windows、Mac和Linux等多个平台上运行,并且在不同平台上展现出对应的UI风格。为了实现这个功能,我们可以使用抽象工厂模式来设计组件库的结构。
首先,我们定义一个抽象工厂接口,用于创建UI组件:
public interface IGUIFactory {IButton createButton();ITextField createTextField();ILabel createLabel();}
然后,我们定义各个具体的工厂类,每个工厂类都可以创建一组相互依赖的UI组件:
public class WindowsGUIFactory implements IGUIFactory {public IButton createButton() {return new WindowsButton();}public ITextField createTextField() {return new WindowsTextField();}public ILabel createLabel() {return new WindowsLabel();}}public class MacGUIFactory implements IGUIFactory {public IButton createButton() {return new MacButton();}public ITextField createTextField() {return new MacTextField();}public ILabel createLabel() {return new MacLabel();}}public class LinuxGUIFactory implements IGUIFactory {public IButton createButton() {return new LinuxButton();}public ITextField createTextField() {return new LinuxTextField();}public ILabel createLabel() {return new LinuxLabel();}}
其中,每个具体工厂类都实现了IGUIFactory接口,并且分别创建了与平台对应的UI组件对象。
接着,我们定义UI组件的抽象接口:
public interface IButton {void display();}public interface ITextField {void display();}public interface ILabel {void display();}
然后,我们定义各个具体的UI组件类:
public class WindowsButton implements IButton {public void display() {System.out.println("Windows style button.");}}public class WindowsTextField implements ITextField {public void display() {System.out.println("Windows style text field.");}}public class WindowsLabel implements ILabel {public void display() {System.out.println("Windows style label.");}}public class MacButton implements IButton {public void display() {System.out.println("Mac style button.");}}public class MacTextField implements ITextField {public void display() {System.out.println("Mac style text field.");}}public class MacLabel implements ILabel {public void display() {System.out.println("Mac style label.");}}public class LinuxButton implements IButton {public void display() {System.out.println("Linux style button.");}}public class LinuxTextField implements ITextField {public void display() {System.out.println("Linux style text field.");}}public class LinuxLabel implements ILabel {public void display() {System.out.println("Linux style label.");}}
最后,我们可以使用抽象工厂模式来创建UI组件库的对象,然后在不同的平台上使用不同的具体工厂类来创建对应的UI组件。例如:
public class Application {private IGUIFactory factory;public Application(IGUIFactory factory) {this.factory = factory;}public void createUI() {IButton button = factory.createButton();ITextField textField = factory.createTextField();ILabel label = factory.createLabel();button.display();textField.display();label.display();}}
public class Client {public static void main(String[] args) {// 创建Windows风格的UI组件库IGUIFactory windowsFactory = new WindowsGUIFactory();Application windowsApp = new Application(windowsFactory);windowsApp.createUI();// 创建Mac风格的UI组件库IGUIFactory macFactory = new MacGUIFactory();Application macApp = new Application(macFactory);macApp.createUI();// 创建Linux风格的UI组件库IGUIFactory linuxFactory = new LinuxGUIFactory();Application linuxApp = new Application(linuxFactory);linuxApp.createUI();}}
在上面的代码中,我们首先创建了三个具体的工厂类,分别代表了Windows、Mac和Linux三个平台。然后,我们使用这些工厂类创建了三个不同的Application对象,并且调用了每个对象的createUI()方法来创建UI组件并展示出来。
在Windows平台上运行上述代码的输出结果如下所示:
cssCopy codeWindows style button.Windows style text field.Windows style label.
在Mac平台上运行上述代码的输出结果如下所示:
Mac style button.Mac style text field.Mac style label.
在Linux平台上运行上述代码的输出结果如下所示:
Linux style button.Linux style text field.Linux style label.
从输出结果可以看出,不同平台的UI组件对象的具体实现是不同的,但是它们都实现了相同的抽象接口。这种设计可以使得我们的UI组件库具有良好的可扩展性,如果我们要支持更多的平台,只需要添加对应的具体工厂类即可
三、总结
在前面的讨论中,我们讲解了工厂模式的基本概念和常见的几种类型,下面我们再介绍一些实际应用场景,以及如何选择适合的工厂模式。
-
实际应用场景
工厂模式在很多实际应用场景中都得到了广泛的应用。下面是一些实际应用场景的示例:
-
数据库连接池。在大多数 Web 应用程序中,数据库连接池都是必需的。通过使用工厂模式,我们可以创建一个可以管理连接的对象池,并在需要时分配连接。这种方法可以避免每次需要连接数据库时都创建一个新连接的开销。
-
文件读取器。在处理文件时,可能需要根据文件类型创建不同的读取器。通过使用工厂模式,我们可以根据文件类型创建不同的文件读取器,从而实现可扩展性和灵活性。
-
网络传输协议。在开发网络应用程序时,可能需要根据不同的传输协议创建不同的对象。通过使用工厂模式,我们可以轻松地根据需要创建不同类型的对象。
-
如何选择适合的工厂模式
在实际应用中,我们需要根据具体情况选择适合的工厂模式。下面是一些指导原则:
-
简单工厂模式。如果只需要创建一个类型的对象,或者对象的创建逻辑比较简单,可以使用简单工厂模式。
-
工厂方法模式。如果需要创建多个相关的对象,并且它们之间的差异比较大,可以使用工厂方法模式。这种模式可以根据需要创建不同的工厂类,每个工厂类可以创建不同的对象。
-
抽象工厂模式。如果需要创建多个相关的对象,并且这些对象之间有复杂的关系,可以使用抽象工厂模式。这种模式可以创建一组相关的对象,并且这些对象之间的关系可以在运行时确定。
综上所述,工厂模式是一种非常常用的设计模式,可以提高代码的可扩展性、灵活性和可维护性。在实际应用中,我们需要根据具体情况选择适合的工厂模式。
本文链接:https://my.lmcjl.com/post/8677.html
4 评论