工厂模式

148 阅读5分钟

简单工厂模式

定义

简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于创建型模式。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承或实现一个父类或接口)的实例。

UML类图

简单工厂模式.drawio.png

具体例子

场景:实现一个简单的翻译功能,要求:能够将一段中文文本翻译成不同的语言版本

/**
 * @Author blackcat
 * @version: 1.0
 * @description:翻译的接口定义
 */
public interface Translator {

    /**
     * 翻译
     *
     * @param content 待翻译的内容
     * @return 翻译的得到的内容
     */
      String translate(String content);
}


import org.springframework.stereotype.Service;

/**
 * @Author blackcat
 * @version: 1.0
 * @description:英语翻译器
 */
@Service
public class EnglishTranslator implements Translator{

    //模拟服务
    @Override
    public String translate(String content) {
         return content+"abc";
    }
}



/**
 * @Author blackcat
 * @version: 1.0
 * @description:日语翻译器
 */
public class JapaneseTranslator implements Translator {

    //模拟服务
    @Override
    public String translate(String content) {
        return content+"めがね";
    }
}


import lombok.Getter;


/**
 * @Author blackcat
 * @version: 1.0
 * @description:语言枚举
 */
@Getter
public enum LanguageEnum {

    CHINESE("chinese", "中文"),

    ENGLISH("english", "英语"),

    JAPANESE("japanese", "日语");

    private String code;

    private String name;

    LanguageEnum(String code, String name) {
        this.code = code;
        this.name = name;
    }
}


import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author blackcat
 * @version: 1.0
 * @description:翻译器工厂
 */
@Component
public class TranslatorFactory {

    @Resource
    private Translator englishTranslator;

    @Resource
    private Translator JapaneseTranslator;

    protected final static Map<String, Translator> translatorFactory = new ConcurrentHashMap<>();

    @PostConstruct
    public void init() {
        translatorFactory.put(LanguageEnum.ENGLISH.getCode(), englishTranslator);
        translatorFactory.put(LanguageEnum.JAPANESE.getCode(), JapaneseTranslator);
    }

    /**
     * 根据语言枚举拿到指定语言的翻译器
     *
     * @param languageEnum 语言枚举
     * @return 指定语言的翻译器
     * @throws Exception 当拿不到翻译器时,抛出此异常
     */
    public static Translator getTranslator(LanguageEnum languageEnum) throws Exception {
        return getTranslator(languageEnum.getCode());
    }

    /**
     * 根据语言编码拿到指定语言的翻译器
     *
     * @param languageCode 语言编码
     * @return 指定语言的翻译器
     * @throws Exception 当拿不到翻译器时,抛出此异常
     */
    public static Translator getTranslator(String languageCode) throws Exception {
        Translator translator = translatorFactory.get(languageCode);
        if (null == translator) {
            throw new Exception("无法翻译成这种语言");
        }
        return translator;
    }

}


import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

/**
 * @Author blackcat
 * @version: 1.0
 * @description:翻译服务
 */
@RestController
@RequestMapping("translate")
public class TranslateController {

    @GetMapping("{code}")
    public ResponseEntity<String> translate(@PathVariable("code") String code,
                                            @RequestParam(value = "content", required = false) String content) {
        try {
            // 调用工厂类的静态方法,传入语言编码,拿到具体的翻译器实例进行翻译
            return ResponseEntity.ok(TranslatorFactory.getTranslator(code).translate(content));
        } catch (Exception e) {
            return ResponseEntity.ok(e.getMessage());
        }
    }
}


源码中的应用

public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> { 
   public static Calendar getInstance(){
        return createCalendar(TimeZone.getDefault(),                       	    Locale.getDefault(Locale.Category.FORMAT));
    }

  private static Calendar createCalendar(TimeZone zone,
                                           Locale aLocale) {
        CalendarProvider provider =
            LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                                 .getCalendarProvider();
        if (provider != null) {
            try {
                return provider.getInstance(zone, aLocale);
            } catch (IllegalArgumentException iae) {
                // fall back to the default instantiation
            }
        }

        Calendar cal = null;

        if (aLocale.hasExtensions()) {
            String caltype = aLocale.getUnicodeLocaleType("ca");
            if (caltype != null) {
                switch (caltype) {
                case "buddhist":
                cal = new BuddhistCalendar(zone, aLocale);
                    break;
                case "japanese":
                    cal = new JapaneseImperialCalendar(zone, aLocale);
                    break;
                case "gregory":
                    cal = new GregorianCalendar(zone, aLocale);
                    break;
                }
            }
        }
        if (cal == null) {
            // If no known calendar type is explicitly specified,
            // perform the traditional way to create a Calendar:
            // create a BuddhistCalendar for th_TH locale,
            // a JapaneseImperialCalendar for ja_JP_JP locale, or
            // a GregorianCalendar for any other locales.
            // NOTE: The language, country and variant strings are interned.
            if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
                cal = new BuddhistCalendar(zone, aLocale);
            } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                       && aLocale.getCountry() == "JP") {
                cal = new JapaneseImperialCalendar(zone, aLocale);
            } else {
                cal = new GregorianCalendar(zone, aLocale);
            }
        }
        return cal;
    }
}

优缺点

优点:

  1. 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
  2. 客户端无需知道所创建具体产品的类名,只需知道参数即可。
  3. 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。

缺点:

  1. 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
  2. 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度。
  3. 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂。
  4. 简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。

工厂模式

定义

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

UML类图

工厂模式.drawio.png

具体的例子

/**
 * @Author blackcat
 * @version: 1.0
 * @description:翻译的接口定义
 */
public interface Translator {

    /**
     * 翻译
     *
     * @param content 待翻译的内容
     * @return 翻译的得到的内容
     */
      String translate(String content);
}


import org.springframework.stereotype.Service;

/**
 * @Author blackcat
 * @version: 1.0
 * @description:英语翻译器
 */
@Service
public class EnglishTranslator implements Translator{

    //模拟服务
    @Override
    public String translate(String content) {
         return content+"abc";
    }
}



/**
 * @Author blackcat
 * @version: 1.0
 * @description:日语翻译器
 */
public class JapaneseTranslator implements Translator {

    //模拟服务
    @Override
    public String translate(String content) {
        return content+"めがね";
    }
}


/**
 * @Author blackcat
 * @version: 1.0
 * @description:创造Translator的工厂类定义
 */
public interface ITranslatorFactory {

    Translator createTranslator();
}


/**
 * @Author blackcat
 * @version: 1.0
 * @description:创建英语翻译器的工厂类
 */
public class EnglishTranslatorFactory implements ITranslatorFactory {

    @Override
    public Translator createTranslator() {
        return new EnglishTranslator();
    }
}


/**
 * @Author blackcat
 * @version: 1.0
 * @description:创建日语翻译器的工厂类
 */
public class JapaneseTranslatorFactory implements ITranslatorFactory {
    @Override
    public Translator createTranslator() {
        return new JapaneseTranslator();
    }
}

优缺点

优点:

工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。

灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。

缺点:

类的个数容易过多,增加复杂度

增加了系统的抽象性和理解难度

抽象工厂模式

定义

抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。在抽象工厂中最明显的一个特点是产品不止一类了,在抽象工厂在提到一个“产品族”的概念。

UML类图

抽象工厂.png

具体的例子

public interface IVideo{
    void record();
}

public interface INote{
    void edit();
}

/**
*
*抽象工厂
*/
public interface CourseFactory{
    INote createNote();
    IVideo createVideo();
}

public JavaVideo implements IVideo{
    public void record(){
        System.out.println("录制java视频");
    }
}

public JavaNote implements INote{
    public void edit(){
        System.out.println("编写java笔记");
    }
}

public JavaCourseFactory implements CourseFactory{
    INote createNote(){
        return new JavaVideo();
    }
    IVideo createVideo(){
        return new JavaNote();
    }
}


public PythonVideo implements IVideo{
    public void record(){
        System.out.println("录制Python视频");
    }
}

public PythonNote implements INote{
    public void edit(){
        System.out.println("编写Python笔记");
    }
}

public PythonCourseFactory implements CourseFactory{
    INote createNote(){
        return new PythonVideo();
    }
    IVideo createVideo(){
        return new PythonNote();
    }
}


优缺点

优点:

当一个族中的多个对象被设计成一起工作时, 它能够保证客户端始终只使用同一个族中的对象。

增加新的族很方便, 无须修改已有系统, 符合“开闭原则”。

缺点:

增加新的等级结构麻烦, 需要对原有系统进行较大的修改, 甚至需要修改抽象层代码,这显然会带来较大的不便, 违背了“开闭原则”。