【设计模式In Java】一、工厂模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/CL_YD/article/details/86675704

工厂模式

简单(静态)工厂模式

定义

简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。

场景

Runtime.getRuntime().exec()方法可以执行操作系统命令,现在需要通过这种方式获取操作系统版本信息,但不同的操作系统执行的命令不同,不同的操作系统交给不同的处理类去处理,这些处理类的创建交给静态工厂完成,客户端只需要传入对应西系统类型就可以返回相应的处理类。

UML类图

在这里插入图片描述
对象的创建全部委托给HostVerFactory,使用时调用工厂类的静态工厂方法,传入具体的操作系统类型,即可获取目标处理类。

代码

simplefactory
示例:

@Test
public void test(){
    String osName = System.getProperty("os.name").toLowerCase();
    String osType = null;
    if(osName.contains("windows")){
        osType = "Windows";
    }else if(osName.contains("linux")){
        osType = "Linux";
    }
    AbstractHostVerHandler hostVerHandler = HostVerFactory.getVerHandler(osType);
    System.out.println(hostVerHandler.getVersion());
}
/**
 * Microsoft Windows [版本 10.0.17134.523]
 */

总结

简单工厂模式一般在业务比较简单的场景下使用,比如上面的操作系统类型,因为操作系统类型是可穷举的,或者是可以限定的。如果业务复杂多变或者实例类型不固定,如果新增一个实例类型,就必须修改静态工厂方法,这就违反了开闭原则,而且随着类型的增加,工厂方法的复杂度可能会越来越高职责过重。

工厂方法模式

定义

工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。工厂方法模式是一种类创建型模式。

场景

现在需要把一个字符串转换成其他格式,比如从驼峰转换成下划线等,不同的格式对字符串单词的拆分方式是一样的,但是对拆分后的单词列表重新拼装方式却是不同的。以后可能有新的格式加进来,希望遵循开闭原则。

UML类图

在这里插入图片描述

代码

factorymethod
示例:

public void test(){
    String text = "factory method test";
    CamelFormatterFactory camelFormatterFactory = new CamelFormatterFactory();
    HyphenFormatterFactory hyphenFormatterFactory = new HyphenFormatterFactory();
    UnderscoreFormatterFactory underscoreFormatterFactory = new UnderscoreFormatterFactory();

    System.out.println(transform(camelFormatterFactory, text));
    System.out.println(transform(hyphenFormatterFactory, text));
    System.out.println(transform(underscoreFormatterFactory, text));
}

private String transform(AbstractFormatterFactory factory, String text){
    return factory.create().transform(text);
}
/**
 FactoryMethodTest
 factory-method-test
 factory_method_test
 */

总结

工厂方法和静态工厂的区别,仅仅是加了一个抽象工厂类,在声明的时候直接声明抽象工厂类,具体实例的创建交给具体的工厂。这样做的好处是:针对不同产品提供不同的工厂类,代码的耦合度更低,新增实例类型时可以不会修改其他工厂和实例类型的代码,遵循开闭原则,甚至可以把类名放在配置文件中,直接通过读取配置文件、动态加载工厂,达到不改一行代码的目的。相较于静态工厂,工厂方法有更好的扩展性和更低的耦合性。

静态工厂和工厂方法的缺点其实很明显:每个工厂只能生产一种产品,假设一个产品由多个零件组成,难道每个零件都要走各自的工厂创建吗?如果这样做,一旦客户端创建了一个错误的零件,最终组合出来的产品就不符合期望,甚至影响整个产品的功能。

工厂方法可以重载,达到不同的初始化效果,甚至可以直接隐藏工厂方法,暴露实例方法的代理。

抽象工厂模式

定义

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。

场景

通过java+ssh在远程主机上自动化部署Java程序,除了部署Java程序,还要部署一个第三方的日志手机和分发程序。因为不同系统的JDK要求不一样,比如CentOS可以使用官方JDK,但IBM的AIX系统只能使用IBM的JDK;CentOS可以使用Filebeat,但Filebeat是用go语言编写的,AIX没有go语言编译器,无法使用Filebeat,只能使用Logstash代替。

UML类图

在这里插入图片描述

代码

abstractfactory
示例:

public void test(){
    AixInitFactory aixInitFactory = new AixInitFactory();
    LinuxInitFactory linuxInitFactory = new LinuxInitFactory();

    HostConfig hostConfig = new HostConfig.HostConfigBuilder()
            .ip("192.168.0.9")
            .username("root")
            .password("root")
            .port(22)
            .build();
    init(aixInitFactory, hostConfig);
    System.out.println("\n----------------------------------------------\n");
    init(linuxInitFactory, hostConfig);
}

private void init(AbstractInitFactory factory, HostConfig hostConfig){
    AbstractJdk jdk = factory.createJdk();
    AbstractLogShipper logShipper = factory.createLogShipper();

    jdk.install(hostConfig);
    jdk.start(hostConfig);

    logShipper.install(hostConfig);
    logShipper.config(hostConfig);
    logShipper.start(hostConfig);
}

总结

抽象工厂可以任意组合产品族而不出错,增加一个产品族也不会对已有代码产生影响,遵循开闭原则;但是另一方便,假设要在产品族中加一个新产品,那势必会导致所有工厂的变更,这是不遵循开闭原则的。

抽象工厂模式的这种性质称为“开闭原则”的倾斜性。这就要求产品一开始的设计就尽量考虑全面。如果添加的产品在大部分产品族中都一样,那么可以在抽象类中提供默认实现,只修改抽象工厂的方法,大部分产品族可以使用默认实现保持不变,其他特殊的产品族再做单独修改,让修改达到最小。

总结

  • 工厂模式使实例的创建与使用隔离,这种隔离会给功能扩展和替换带来便利,符合开闭原则;
  • 协同开发的情况下,保证大家使用的是同一种模式、方法、类;
  • 无论哪种工厂模式都有一定的开闭原则倾斜,可能会导致抽象层代码的修改,需要在设计阶段尽量全面。

猜你喜欢

转载自blog.csdn.net/CL_YD/article/details/86675704