设计模式之工厂设计模式

原创 悟 老汉聊技术 2023-04-16 00:00 发表于四川

工厂模式是一种常用的创建型设计模式,它通过一个共同的接口来创建一些相关或相互依赖的对象,而无需指定其具体的类。

一、工厂模式分类

工厂模式主要分为以下几种:

  1. 简单工厂模式:由一个工厂类根据传入的参数,决定创建哪种产品类的实例。

  2. 工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪个类。使一个类的实例化延迟到其子类。

  3. 抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

二、工厂模式详解

​下面分别详细讲解每一种工厂模式,并结合实际应用场景举例,给出示例代码。

  1. ​简单工厂模式

简单工厂模式又叫静态工厂方法模式,它属于类创建型模式。简单工厂模式是由一个工厂类根据传入的参数,动态决定创建哪种产品类的实例。简单工厂模式适用于工厂类负责创建的对象比较少的场景。

应用场景:

假设一个系统需要记录不同种类的日志信息,例如文件日志、数据库日志、控制台日志等。系统需要提供一个可以按照用户要求创建不同种类日志的工厂类。

示例代码:

首先定义一个日志接口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();    }}

  1. 工厂方法模式

工厂方法模式是一种常见的创建型设计模式,它定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法模式使一个类的实例化延迟到其子类。

应用场景:

假设一个系统需要记录不同种类的日志信息,例如文件日志、数据库日志、控制台日志等。系统需要提供一个可以按照用户要求创建不同种类日志的工厂接口,并让具体工厂类去实现不同种类的日志对象创建。

示例代码:

首先定义一个日志接口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();    }}

  1. 抽象工厂模式

抽象工厂模式是一种常用的创建型设计模式,它提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。抽象工厂模式适用于需要创建一组相关或相互依赖的对象时,可以通过一个工厂接口来实现。

应用场景:

假设一个系统需要提供一个图形界面库,其中包含不同种类的界面元素,例如按钮、文本框、复选框等。每种元素又分为不同的主题风格,例如 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风格的按钮、文本框和复选框对象。

抽象工厂模式通常适用于以下情况:

  1. 系统需要一组相关或相互依赖的对象,并且这些对象的创建过程需要统一管理。

  2. 系统不应依赖于产品类实例如何被创建、组合和表达的细节,这些细节应该被封装在一个共同的接口中。

  3. 系统中有多个产品族,而每次只使用其中某一族产品。例如本例中,我们创建了Windows、Mac和Linux三个产品族,但每次只使用其中的一个。

抽象工厂模式的优点包括:

  1. 抽象工厂模式将具体产品的类名封装起来,使得客户端不需要知道它们的实现细节,只需要知道它们的共同接口即可。

  2. 抽象工厂模式使得客户端不依赖于具体产品类,而是依赖于抽象工厂接口和抽象产品接口,这样可以在不修改客户端代码的情况下改变具体工厂类和产品类。

接下来,我们来看一个更加实际的例子,使用抽象工厂模式创建一个跨平台的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组件库具有良好的可扩展性,如果我们要支持更多的平台,只需要添加对应的具体工厂类即可

三、总结

在前面的讨论中,我们讲解了工厂模式的基本概念和常见的几种类型,下面我们再介绍一些实际应用场景,以及如何选择适合的工厂模式。

  1. 实际应用场景

工厂模式在很多实际应用场景中都得到了广泛的应用。下面是一些实际应用场景的示例:

  • 数据库连接池。在大多数 Web 应用程序中,数据库连接池都是必需的。通过使用工厂模式,我们可以创建一个可以管理连接的对象池,并在需要时分配连接。这种方法可以避免每次需要连接数据库时都创建一个新连接的开销。

  • 文件读取器。在处理文件时,可能需要根据文件类型创建不同的读取器。通过使用工厂模式,我们可以根据文件类型创建不同的文件读取器,从而实现可扩展性和灵活性。

  • 网络传输协议。在开发网络应用程序时,可能需要根据不同的传输协议创建不同的对象。通过使用工厂模式,我们可以轻松地根据需要创建不同类型的对象。

  1. 如何选择适合的工厂模式

在实际应用中,我们需要根据具体情况选择适合的工厂模式。下面是一些指导原则:

  • 简单工厂模式。如果只需要创建一个类型的对象,或者对象的创建逻辑比较简单,可以使用简单工厂模式。

  • 工厂方法模式。如果需要创建多个相关的对象,并且它们之间的差异比较大,可以使用工厂方法模式。这种模式可以根据需要创建不同的工厂类,每个工厂类可以创建不同的对象。

  • 抽象工厂模式。如果需要创建多个相关的对象,并且这些对象之间有复杂的关系,可以使用抽象工厂模式。这种模式可以创建一组相关的对象,并且这些对象之间的关系可以在运行时确定。

综上所述,工厂模式是一种非常常用的设计模式,可以提高代码的可扩展性、灵活性和可维护性。在实际应用中,我们需要根据具体情况选择适合的工厂模式。

本文链接:https://my.lmcjl.com/post/8677.html

展开阅读全文

4 评论

留下您的评论.