JYM 设计模式系列-工厂模式,让你的代码更优雅!!!

4,361 阅读9分钟

觉得不错请按下图操作,掘友们,哈哈哈!!! image.png

概述设计模式分类

总体来说设计模式分为三大类:

  • 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

  • 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

  • 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

一:创建模式(5种)

工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

1. 工厂模式

1.1 简单工厂模式

Factory是用于创建其他对象的对象。它提供了一个静态方法来创建并返回不同类的对象,以便隐藏实现逻辑并使客户端代码专注于使用而不是对象初始化和管理。

二话不说上一个demo:在这个例子中,我们来通过制造硬币业务讲解。CoinFactory是工厂类,它提供了一个静态方法来创建不同类型的硬币。

image.png

Coin 接口:

public interface Coin {

  String getDescription();

}

Coin工厂:

public class CoinFactory {

      /**
       *  工厂方法将硬币类型作为参数,并调用相应的类
       */
      public static Coin getCoin(CoinType type) {
        return type.getConstructor().get();
      }
    }

不同类型硬币的枚举:

@RequiredArgsConstructor
@Getter
public enum CoinType {

  COPPER(CopperCoin::new),
  GOLD(GoldCoin::new);

  private final Supplier<Coin> constructor;
}

铜硬币的实现:

public class CopperCoin implements Coin {

  static final String DESCRIPTION = "This is a copper coin.";

  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}

金硬币的实现:

public class GoldCoin implements Coin {

  static final String DESCRIPTION = "This is a gold coin.";

  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}

主类:Factory用于创建其他对象的对象。它提供了一个静态方法来 创建并返回不同类的对象,以便隐藏实现逻辑 并使客户端代码专注于使用而不是对象初始化和管理

@Slf4j
public class App {

  /**
   * Program main entry point.
   */
  public static void main(String[] args) {
    LOGGER.info("The alchemist begins his work.");
    var coin1 = CoinFactory.getCoin(CoinType.COPPER);
    var coin2 = CoinFactory.getCoin(CoinType.GOLD);
    LOGGER.info(coin1.getDescription());
    LOGGER.info(coin2.getDescription());
  }
}

在这个例子中,炼金术士制造硬币。CoinFactory是工厂类提供一个静态方法来创建不同类型的硬币。

1.2 工厂方法

工厂方法模式(FACTORY METHOD)是一种常用的类创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。它的核心结构有四个角色,分别是抽象工厂;具体工厂;抽象产品;具体产品。

适用场景

如果无法预知对象确切类别及其依赖关系时,可使用工厂方法。 工厂方法将创建产品的代码与实际使用产品的代码分离, 从而能在不影响其他代码的情况下扩展产品创建部分代码。 例如, 如果需要向应用中添加一种新产品, 你只需要开发新的创建者子类, 然后重写其工厂方法即可。

实现方式

  1. 让所有产品都遵循同一接口。该接口必须声明对所有产品都有意义的方法。
  2. 在创建类中添加一个空的工厂方法。该方法的返回类型必须遵循通用的产品接口。

以不同种类的铁匠铸造武器为demo:

image.png

Blacksmith 铁匠 包含用于生成对象的方法的接口:

public interface Blacksmith {

  Weapon manufactureWeapon(WeaponType weaponType);

}

WeaponType:武器类型枚举

/**
 * WeaponType enumeration.
 */
@RequiredArgsConstructor
public enum WeaponType {

  SHORT_SWORD("short sword"),
  SPEAR("spear"),
  AXE("axe"),
  UNDEFINED("");

  private final String title;

  @Override
  public String toString() {
    return title;
  }
}

Weapon 武器类型接口:

/**
 * Weapon interface.
 */
public interface Weapon {

  WeaponType getWeaponType();

}

精灵铁匠:用于创建新对象的具体子类:

public class ElfBlacksmith implements Blacksmith {

  private static final Map<WeaponType, ElfWeapon> ELFARSENAL;

  static {
    ELFARSENAL = new EnumMap<>(WeaponType.class);
    Arrays.stream(WeaponType.values()).forEach(type -> ELFARSENAL.put(type, new ElfWeapon(type)));
  }

  @Override
  public Weapon manufactureWeapon(WeaponType weaponType) {
    return ELFARSENAL.get(weaponType);
  }

  @Override
  public String toString() {
    return "The elf blacksmith";
  }
}

Elf Weapon 武器:

@RequiredArgsConstructor
@Getter
public class ElfWeapon implements Weapon {

  private final WeaponType weaponType;

  @Override
  public String toString() {
    return "an elven " + weaponType;
  }
}

兽人铁匠:用于创建新对象的具体子类:

public class OrcBlacksmith implements Blacksmith {

  private static final Map<WeaponType, OrcWeapon> ORCARSENAL;

  static {
    ORCARSENAL = new EnumMap<>(WeaponType.class);
    Arrays.stream(WeaponType.values()).forEach(type -> ORCARSENAL.put(type, new OrcWeapon(type)));
  }

  @Override
  public Weapon manufactureWeapon(WeaponType weaponType) {
    return ORCARSENAL.get(weaponType);
  }

  @Override
  public String toString() {
    return "The orc blacksmith";
  }
}

OrcWeapon 武器:

@RequiredArgsConstructor
@Getter
public class OrcWeapon implements Weapon {

  private final WeaponType weaponType;

  @Override
  public String toString() {
    return "an orcish " + weaponType;
  }
}

主类:

@Slf4j
public class App {

 private static final String MANUFACTURED = "{} manufactured {}";

 /**
  * Program entry point.
  * @param args command line args
  */
 public static void main(String[] args) {

   Blacksmith blacksmith = new OrcBlacksmith();
   Weapon weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
   LOGGER.info(MANUFACTURED, blacksmith, weapon);
   weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
   LOGGER.info(MANUFACTURED, blacksmith, weapon);

   blacksmith = new ElfBlacksmith();
   weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
   LOGGER.info(MANUFACTURED, blacksmith, weapon);
   weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
   LOGGER.info(MANUFACTURED, blacksmith, weapon);
 }
}

工厂方法是一种创造性的设计模式,它使用工厂方法来处理 创建对象时没有指定要创建的对象的确切类的问题。 这是通过调用在接口中指定的工厂方法来创建对象来完成的 并由子类实现,或在基类中实现并可选地被覆盖 派生类——而不是通过调用构造函数。

在这个工厂方法示例中,我们有一个接口 Blacksmith 和一个方法 创建对象(manufactureWeapon)。 具体的子类( OrcBlacksmith, ElfBlacksmith) 然后覆盖该方法以生成他们喜欢的对象

1.3 抽象工厂

抽象工厂(AbstractFactory)模式提供了一种封装一组独立工厂的方法有一个共同的目标,而不指定它们的具体类。正常使用情况下,客户端软件创建抽象工厂的具体实现,然后使用泛型接口,用于创建作为主题一部分的具体对象。客户端不知道(或不关心)它从每个内部工厂获得哪些具体对象,因为它只使用他们产品的通用接口。这种模式将细节分开一组对象的实现从它们的一般用法和依赖于对象组合,因为对象创建是在工厂接口中公开的方法中实现的。

抽象工厂模式的本质是一个工厂接口 (KingdomFactory)及其实现ElfKingdomFactory,OrcKingdomFactory。该示例使用创建国王、城堡和军队的具体实现。

image.png

King 国王接口:

public interface King {

  String getDescription();
}

Army 军队接口:

public interface Army {

  String getDescription();
}

Castle:城堡接口

public interface Castle {

  String getDescription();
}

KingdomFactory:王国工厂

public interface KingdomFactory {

  Castle createCastle();

  King createKing();

  Army createArmy();

}

帮助KingdomFactory 生产 bean的类

@Getter
@Setter
public class Kingdom {

  private King king;
  private Castle castle;
  private Army army;

  /**
   * The factory of kingdom factories.
   */
  public static class FactoryMaker {

    /**
     * Enumeration for the different types of Kingdoms.
     */
    public enum KingdomType {
      ELF, ORC
    }

    /**
     * The factory method to create KingdomFactory concrete objects.
     */
    public static KingdomFactory makeFactory(KingdomType type) {
      return switch (type) {
        case ELF -> new ElfKingdomFactory();
        case ORC -> new OrcKingdomFactory();
        default -> throw new IllegalArgumentException("KingdomType not supported.");
      };
    }
  }
}

ElfArmy :精灵的军队

public class ElfArmy implements Army {

  static final String DESCRIPTION = "This is the elven army!";

  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}

ElfCastle:精灵城堡

public class ElfCastle implements Castle {

  static final String DESCRIPTION = "This is the elven castle!";

  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}

ElfKing 精灵国王:

public class ElfKing implements King {

  static final String DESCRIPTION = "This is the elven king!";

  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}

精灵国工厂:

public class ElfKingdomFactory implements KingdomFactory {

  @Override
  public Castle createCastle() {
    return new ElfCastle();
  }

  @Override
  public King createKing() {
    return new ElfKing();
  }

  @Override
  public Army createArmy() {
    return new ElfArmy();
  }

}

兽人军队:

public class OrcArmy implements Army {

  static final String DESCRIPTION = "This is the orc army!";

  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}

兽人城堡:

public class OrcCastle implements Castle {

  static final String DESCRIPTION = "This is the orc castle!";

  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}

兽人国王:

public class OrcKing implements King {

  static final String DESCRIPTION = "This is the orc king!";

  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}

兽人王国工厂:

public class OrcKingdomFactory implements KingdomFactory {

  @Override
  public Castle createCastle() {
    return new OrcCastle();
  }

  @Override
  public King createKing() {
    return new OrcKing();
  }

  @Override
  public Army createArmy() {
    return new OrcArmy();
  }
}

主类:

@Slf4j
public class App implements Runnable {

  private final Kingdom kingdom = new Kingdom();

  public Kingdom getKingdom() {
    return kingdom;
  }

  /**
   * Program entry point.
   *
   * @param args command line args
   */
  public static void main(String[] args) {
    var app = new App();
    app.run();
  }

  @Override
  public void run() {
    LOGGER.info("elf kingdom");
    createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
    LOGGER.info(kingdom.getArmy().getDescription());
    LOGGER.info(kingdom.getCastle().getDescription());
    LOGGER.info(kingdom.getKing().getDescription());

    LOGGER.info("orc kingdom");
    createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
    LOGGER.info(kingdom.getArmy().getDescription());
    LOGGER.info(kingdom.getCastle().getDescription());
    LOGGER.info(kingdom.getKing().getDescription());
  }

  /**
   * Creates kingdom.
   * @param kingdomType type of Kingdom
   */
  public void createKingdom(final Kingdom.FactoryMaker.KingdomType kingdomType) {
    final KingdomFactory kingdomFactory = Kingdom.FactoryMaker.makeFactory(kingdomType);
    kingdom.setKing(kingdomFactory.createKing());
    kingdom.setCastle(kingdomFactory.createCastle());
    kingdom.setArmy(kingdomFactory.createArmy());
  }
}

抽象工厂模式提供了一种方法来封装一组具有共同主题的独立工厂,而无需指定它们的具体类。在正常使用中,客户端软件创建抽象工厂的具体实现,然后使用工厂的通用接口创建作为主题一部分的具体对象。客户不知道(或不关心)它从这些内部工厂中的每一个获得了哪些具体对象, 因为它只使用它们产品的通用接口。这种模式将一组对象的实现细节与它们的一般用法分开,并依赖于对象组合,因为对象创建是在工厂接口中公开的方法中实现的。

这个例子中抽象工厂模式的本质是工厂接口({@link KingdomFactory})及其实现({@link ElfKingdomFactory}、{@link OrcKingdomFactory})。该示例使用两个具体实现来创建国王、城堡和军队。

1.4 Factory kit 模式

Factory kit 是一种创建模式,它定义了一个不可变内容的工厂,具有分离的builder 和 factory 接口,以处理直接在 factory kit 实例中创建指定对象之一的问题。

image.png

具体demo

定义一个武器接口:

public interface Weapon {
}

功能接口,工厂套件设计模式的一个例子。 本地创建的实例提供了一个机会来严格定义工厂实例将能够创建哪些对象类型。Factory 是 Builder 的占位符使用 WeaponFactory#create(WeaponType) 方法初始化新对象

public interface WeaponFactory {

  /**
   * Creates an instance of the given type.
   *
   * @param name representing enum of an object type to be created.
   * @return new instance of a requested class implementing {@link Weapon} interface.
   */
  Weapon create(WeaponType name);

  /**
   * Creates factory - placeholder for specified {@link Builder}s.
   *
   * @param consumer for the new builder to the factory.
   * @return factory with specified {@link Builder}s
   */
  static WeaponFactory factory(Consumer<Builder> consumer) {
    var map = new HashMap<WeaponType, Supplier<Weapon>>();
    consumer.accept(map::put);
    return name -> map.get(name).get();
  }
}

Builder:允许将具有名称的构建器添加到工厂的功能接口

public interface Builder {
  void add(WeaponType name, Supplier<Weapon> supplier);
}

代表 斧头 的类:

public class Axe implements Weapon {
  @Override
  public String toString() {
    return "Axe";
  }
}

代表弓的类:

public class Bow implements Weapon {
  @Override
  public String toString() {
    return "Bow";
  }
}

代表矛的类:

public class Spear implements Weapon {
  @Override
  public String toString() {
    return "Spear";
  }
}

代表剑的类:

public class Sword implements Weapon {
  @Override
  public String toString() {
    return "Sword";
  }
}

武器类型的枚举:

public enum WeaponType {
  SWORD,
  AXE,
  BOW,
  SPEAR
}

主类:

@Slf4j
public class App {

  /**
   * Program entry point.
   *
   * @param args command line args
   */
  public static void main(String[] args) {
    var factory = WeaponFactory.factory(builder -> {
      builder.add(WeaponType.SWORD, Sword::new);
      builder.add(WeaponType.AXE, Axe::new);
      builder.add(WeaponType.SPEAR, Spear::new);
      builder.add(WeaponType.BOW, Bow::new);
    });
    var list = new ArrayList<Weapon>();
    list.add(factory.create(WeaponType.AXE));
    list.add(factory.create(WeaponType.SPEAR));
    list.add(factory.create(WeaponType.SWORD));
    list.add(factory.create(WeaponType.BOW));
    list.forEach(weapon -> LOGGER.info("{}", weapon.toString()));
  }
}

在给定的示例中,WeaponFactory表示工厂套件,其中包含四个 Builder,用于创建实现 Weapon接口的类的新对象。

它们中的每一个都可以使用 WeaponFactory#create(WeaponType) 方法调用,其中 一个输入表示 WeaponType 的一个实例,需要在工厂实例中显式映射所需的类类型。