欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 资讯 > Spring 设计模式之工厂模式

Spring 设计模式之工厂模式

2024/10/25 1:37:25 来源:https://blog.csdn.net/qq_20236937/article/details/143186445  浏览:    关键词:Spring 设计模式之工厂模式

Spring 设计模式之工厂模式

  • 一、简单工厂模式(静态工厂模式)
    • Spring框架中的体现
    • 举例说明
    • Java代码实现
  • 二、工厂方法模式
    • 举例说明
    • Java代码示例
  • 三、抽象工厂模式
    • 举例说明
    • Java代码示例

在软件开发领域,设计模式 是解决常见问题的最佳实践。
Spring 框架作为 Java 生态中的佼佼者,其成功在很大程度上 归功于对设计模式的巧妙运用。
“Spring 中用到了哪些设计模式?”,这个问题,在 面试 中也比较常见,在此进行整理。

一、简单工厂模式(静态工厂模式)

简单工厂模式又叫静态工厂方法模式,就是建立一个工厂类(是类的形式,而不是接口),对实现了同一接口的一些类进行实例的创建。
其核心是 由一个工厂类根据传入的参数,动态决定创建哪一个产品类的实例。

优点

  1. 责任分割:工厂类包含判断逻辑,决定何时创建哪个产品实例,客户端仅负责“消费”产品。
  2. 灵活性:根据外界信息决定创建哪个具体对象,客户端无需直接创建对象。
  3. 低耦合:外界与具体产品类隔离,降低耦合性。
  4. 结构优化:明确区分职责和权力,利于软件体系结构优化。

缺点

  1. 扩展困难:增加或删除产品需修改工厂逻辑,系统扩展性受限。
  2. 违背OCP:修改工厂逻辑可能导致过于复杂,违背开放-封闭原则(对新增开放,对修改关闭)。
  3. 无法继承:静态工厂方法使得工厂角色无法形成基于继承的等级结构。

Spring框架中的体现

举例说明

您走进了一家名为“万能奶茶店”的饮品店。这家店里只有一位店员(相当于工厂类),他负责制作店里所有种类的奶茶。当您告诉店员您想喝的奶茶类型(比如珍珠奶茶、抹茶拿铁或草莓奶茶)时,店员会根据您的要求为您精心制作一杯(即创建奶茶对象)。

然而,如果这家奶茶店想要推出新口味的奶茶(比如芒果奶茶),店员就需要学习新口味的制作方法,并且还要在菜单上添加这个新选项。这就意味着店员(即工厂类)的职责范围需要扩大,因此其代码也需要相应地进行修改,以支持这种新口味的奶茶。

这种模式下,每当有新产品加入时,都需要对工厂类进行修改,这可能会影响到系统的稳定性和可维护性。

Java代码实现

下面是一个使用简单工厂模式来实现上述场景的Java示例。

知识小贴士:
咖啡对象也可以用类来创建,但是如果是类的话,就必须把咖啡类定义为抽象类(public abstract class MilkTea )是为了强制子类实现必要的方法,防止直接实例化,以及(可选地)提供共享代码。

// 奶茶类,作为所有奶茶的基类  
interface MilkTea {  // 制作奶茶的方法  public abstract void make();  
}  // 珍珠奶茶类  
class PearlMilkTea implements MilkTea {  @Override  public void make() {  System.out.println("制作珍珠奶茶");  }  
}  // 抹茶拿铁类  
class MatchaLatte implements MilkTea {  @Override  public void make() {  System.out.println("制作抹茶拿铁");  }  
}  // 草莓奶茶类  
class StrawberryMilkTea implements MilkTea {  @Override  public void make() {  System.out.println("制作草莓奶茶");  }  
}  // 简单工厂类,负责创建所有种类的奶茶  
class SimpleFactory {  // 根据奶茶类型创建对应的奶茶对象  public static MilkTea createMilkTea(String type) {  switch (type) {  case "pearl":  return new PearlMilkTea();  case "matcha":  return new MatchaLatte();  case "strawberry":  return new StrawberryMilkTea();  default:  throw new IllegalArgumentException("未知的奶茶类型");  }  }  
}  // 客户端测试类  
public class SimpleFactoryClient {  public static void main(String[] args) {  MilkTea tea1 = SimpleFactory.createMilkTea("pearl");  tea1.make(); // 输出:制作珍珠奶茶  MilkTea tea2 = SimpleFactory.createMilkTea("matcha");  tea2.make(); // 输出:制作抹茶拿铁  // 如果添加新口味的奶茶,比如芒果奶茶,需要修改SimpleFactory类  }  
}

如果这家奶茶店想要推出新口味的奶茶(比如芒果奶茶),店员就需要学习新口味的制作方法,并且还要在菜单上添加这个新选项。这就意味着店员(即工厂类)的职责范围需要扩大,因此其代码也需要相应地进行修改,以支持这种新口味的奶茶。

// 新增芒果奶茶类  
class MangoMilkTea implements MilkTea {  @Override  public void make() {  System.out.println("制作芒果奶茶");  }  
}  // 简单工厂类,负责创建所有种类的奶茶(已修改以支持芒果奶茶)  
class SimpleFactory {  // 根据奶茶类型创建对应的奶茶对象(已修改以支持芒果奶茶)  public static MilkTea createMilkTea(String type) {  switch (type) {  case "pearl":  return new PearlMilkTea();  case "matcha":  return new MatchaLatte();  case "strawberry":  return new StrawberryMilkTea();  case "mango": // 新增的芒果奶茶选项  return new MangoMilkTea();  default:  throw new IllegalArgumentException("未知的奶茶类型");  }  }  
}  // 客户端测试类(可以添加测试芒果奶茶的代码)  
public class SimpleFactoryClient {  public static void main(String[] args) {  MilkTea tea1 = SimpleFactory.createMilkTea("pearl");  tea1.make(); // 输出:制作珍珠奶茶  MilkTea tea2 = SimpleFactory.createMilkTea("matcha");  tea2.make(); // 输出:制作抹茶拿铁  MilkTea tea3 = SimpleFactory.createMilkTea("strawberry");  tea3.make(); // 输出:制作草莓奶茶  // 测试新口味的芒果奶茶  MilkTea tea4 = SimpleFactory.createMilkTea("mango");  tea4.make(); // 输出:制作芒果奶茶  }  
}

如果 类存在@Autowired 的使用时,new 对象的操作就需要换成 ApplicationContext 去获取

// 珍珠奶茶类,现在是一个 Spring 组件  
@Component  
class PearlMilkTea implements MilkTea {  @Autowired private PearMapper pearMapper;  @Override  public void make() {  // 使用 pearMapper 做一些事情(例如查询数据库)  pearMapper.select()// ...  System.out.println("制作珍珠奶茶");  }  
}  class SimpleFactory implements ApplicationContextAware {ApplicationContext applicationContext;// 根据奶茶类型创建对应的奶茶对象  public static MilkTea createMilkTea(String type) {switch (type) {case "pearl":return applicationContext.getBean(PearlMilkTea.Class);case "matcha":return new MatchaLatte();case "strawberry":return new StrawberryMilkTea();default:throw new IllegalArgumentException("未知的奶茶类型");}}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext=applicationContext;}
}

二、工厂方法模式

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

优点

  1. 单一职责:每个具体工厂类只负责创建一种产品,代码更加简洁。
  2. 扩展性强:完全满足开闭原则(OCP:对新增开放,对修改关闭),新增产品类时无需修改已有代码,只需新增具体产品类和对应工厂类。

缺点

  1. 增加开发量:每增加一个新产品,都需要新增一个具体产品类和一个对应的具体工厂类,增加了额外的开发工作量。
  2. 维护复杂:当需要修改多个产品类时,可能需要同时修改多个对应的工厂类,维护成本增加。

举例说明

您来到了一个奶茶一条街,这里有多家不同品牌的奶茶店,比如“A品牌奶茶店”和“B品牌奶茶店”, 奶茶店(品牌) 本身就相当于工厂。每家店都有自己的特色奶茶(比如珍珠奶茶、抹茶拿铁和草莓奶茶),并且每家店都有自己的店员(相当于具体工厂类)来负责制作这些奶茶。

您可以根据自己的喜好选择一家奶茶店,然后走进店里告诉店员您想喝的奶茶类型。
店员会根据自己店铺的特色为您制作一杯奶茶。
如果某家店想要推出新口味的奶茶(比如芒果奶茶),他们只需要在自己的店铺里添加这种新口味的奶茶,并培训店员掌握新的制作方法。
这样,其他店铺就不会受到影响,因为每家店都有自己的店员和独特的制作流程。

这种模式下,新增产品时只需要修改对应的具体工厂类,而无需修改工厂接口或现有的其他具体工厂类,从而提高了系统的扩展性和灵活性。

Java代码示例

// 奶茶接口  
interface MilkTea {  void make();  
}  // 珍珠奶茶类  
class PearlMilkTeaImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作珍珠奶茶");  }  
}  // 抹茶拿铁类  
class MatchaLatteImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作抹茶拿铁");  }  
}  // 草莓奶茶类  
class StrawberryMilkTeaImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作草莓奶茶");  }  
}  // 工厂接口  
interface MilkTeaFactory {  MilkTea createMilkTea();  
}  // A品牌奶茶店工厂类  
class BrandAMilkTeaFactory implements MilkTeaFactory {  @Override  public MilkTea createMilkTea() {  return new PearlMilkTeaImpl(); // 假设A品牌只卖珍珠奶茶  }  
}  // B品牌奶茶店工厂类  
class BrandBMilkTeaFactory implements MilkTeaFactory {  @Override  public MilkTea createMilkTea() {  return new MatchaLatteImpl(); // 假设B品牌只卖抹茶拿铁  }  
}  // 客户端测试类  
public class FactoryMethodClient {  public static void main(String[] args) {  MilkTeaFactory factoryA = new BrandAMilkTeaFactory();  MilkTea teaA = factoryA.createMilkTea();  teaA.make(); // 输出:制作珍珠奶茶  MilkTeaFactory factoryB = new BrandBMilkTeaFactory();  MilkTea teaB = factoryB.createMilkTea();  teaB.make(); // 输出:制作抹茶拿铁  // 如果A品牌想要推出新口味的奶茶,// 比如芒果奶茶,只需要在BrandAMilkTeaFactory中添加新的实现  }  
}

如果A品牌奶茶店想要推出新口味的奶茶,比如芒果奶茶

// 奶茶接口  
interface MilkTea {  void make();  
}  // 珍珠奶茶类  
class PearlMilkTeaImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作珍珠奶茶");  }  
}  // 抹茶拿铁类  
class MatchaLatteImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作抹茶拿铁");  }  
}  // 草莓奶茶类  
class StrawberryMilkTeaImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作草莓奶茶");  }  
}  // 新增芒果奶茶类  
class MangoMilkTeaImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作芒果奶茶");  }  
}  // 奶茶类型枚举  
enum MilkTeaType {  PEARL,  MATCHA_LATTE,  STRAWBERRY,  MANGO // 新增芒果奶茶类型  
}  // 工厂接口(稍作修改以支持类型参数)  
interface MilkTeaFactory {  MilkTea createMilkTea(MilkTeaType type); // 引入类型参数  
}  // A品牌奶茶店工厂类(修改以支持多种奶茶)  
class BrandAMilkTeaFactory implements MilkTeaFactory {  @Override  public MilkTea createMilkTea(MilkTeaType type) {  switch (type) {  case PEARL:  return new PearlMilkTeaImpl();  case MANGO: // 新增对芒果奶茶的支持  return new MangoMilkTeaImpl();  default:  throw new IllegalArgumentException("Unsupported MilkTeaType: " + type);  }  }  
}  // B品牌奶茶店工厂类(保持不变,但也可以按类似方式扩展)  
class BrandBMilkTeaFactory implements MilkTeaFactory {  @Override  public MilkTea createMilkTea(MilkTeaType type) {  // 这里为了简单起见,我们只提供一种奶茶,但可以根据需要扩展  if (type == MilkTeaType.MATCHA_LATTE) {  return new MatchaLatteImpl();  } else {  throw new IllegalArgumentException("Unsupported MilkTeaType: " + type);  }  }  
}  // 客户端测试类  
public class FactoryMethodClient {  public static void main(String[] args) {  MilkTeaFactory factoryA = new BrandAMilkTeaFactory();  MilkTea teaA1 = factoryA.createMilkTea(MilkTeaType.PEARL);  teaA1.make(); // 输出:制作珍珠奶茶  MilkTea teaA2 = factoryA.createMilkTea(MilkTeaType.MANGO); // 新增对芒果奶茶的创建  teaA2.make(); // 输出:制作芒果奶茶  MilkTeaFactory factoryB = new BrandBMilkTeaFactory();  MilkTea teaB = factoryB.createMilkTea(MilkTeaType.MATCHA_LATTE);  teaB.make(); // 输出:制作抹茶拿铁  }  
}

三、抽象工厂模式

定义了一个接口用于创建相关或依赖对象的家族,而无需明确指定具体类。
该模式是对工厂方法模式的进一步升级,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

优点:

  1. 高内聚低耦合:抽象工厂模式将产品的创建与使用分离,降低了客户端代码与产品类之间的耦合度,同时产品族内的产品以高内聚的形式存在,有助于代码的维护和管理。
  2. 扩展性好:完全满足开闭原则(OCP:对新增开放,对修改关闭),当需要添加新的产品族时,只需要添加一个新的具体工厂类和相应的产品类,而不需要修改原有的客户端代码。
  3. 灵活性高:通过抽象工厂模式设计,系统可以更加灵活地应对需求的变化,新增组件或平台时,只需新增新的抽象组件和具体平台工厂,无需修改已有代码。

缺点:

  1. 增加复杂性:抽象工厂模式增加了系统的抽象性和复杂性,可能导致系统难以理解和维护。
  2. 扩展新产品困难:如果只需要添加新的产品而不是新的产品族,那么抽象工厂模式可能会变得笨拙,因为需要修改所有的工厂接口和工厂实现类。

举例说明

您来到了一个更加高级的奶茶广场,这里不仅有奶茶店,还有卖杯子、吸管等配件的店铺。而且,这些店铺都是连锁经营的,比如“热带风味奶茶店”和“经典风味奶茶店”,它们不仅提供奶茶,还提供与奶茶风格相匹配的杯子和吸管等配件。

您可以选择自己喜欢的奶茶店品牌,然后走进这家店。在这里,您不仅可以喝到他们特色的奶茶,还可以买到与奶茶风格相匹配的杯子和吸管等配件。这些产品都是一系列相互关联的,共同构成了一个产品族。

如果某家店想要推出新口味的奶茶或者新风格的杯子和吸管(比如蓝莓奶茶或陶瓷杯子),他们只需要在自己的品牌内部进行更新和调整。这样,您就可以在不同的品牌之间自由选择,并且每次都能得到一整套风格一致的奶茶及其配件。

这种模式下,新增产品族时只需要在对应的具体工厂类中添加新的产品创建方法,而无需修改抽象工厂接口或现有的其他具体工厂类(除非新增的产品引入了新的产品等级)。这进一步提高了系统的扩展性和灵活性。

Java代码示例

// 奶茶接口  
interface MilkTea {  void make();  
}  // 杯子接口  
interface Cup {  void show();  
}  // 珍珠奶茶类  
class PearlMilkTeaImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作珍珠奶茶");  }  
}  // 抹茶拿铁类  
class MatchaLatteImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作抹茶拿铁");  }  
}  // 塑料杯类  
class PlasticCupImpl implements Cup {  @Override  public void show() {  System.out.println("这是塑料杯");  }  
}  // 陶瓷杯类  
class CeramicCupImpl implements Cup {  @Override  public void show() {  System.out.println("这是陶瓷杯");  }  
}  // 抽象工厂接口  
interface AbstractFactory {  MilkTea createMilkTea();  Cup createCup();  
}  // 热带风味奶茶店工厂类  
class TropicalFlavorFactory implements AbstractFactory {  @Override  public MilkTea createMilkTea() {  //制作珍珠奶茶return new PearlMilkTeaImpl();  }  @Override  public Cup createCup() { //塑料杯return new PlasticCupImpl();  }  
}  // 经典风味奶茶店工厂类  
class ClassicFlavorFactory implements AbstractFactory {  @Override  public MilkTea createMilkTea() {  //制作抹茶拿铁return new MatchaLatteImpl();  }  @Override  public Cup createCup() { //陶瓷杯return new CeramicCupImpl();  }  
}  // 客户端测试类  
public class AbstractFactoryClient {  public static void main(String[] args) {  AbstractFactory factory1 = new TropicalFlavorFactory();  MilkTea tea1 = factory1.createMilkTea();  Cup cup1 = factory1.createCup();  tea1.make(); // 输出:制作珍珠奶茶  cup1.show(); // 输出:这是塑料杯  AbstractFactory factory2 = new ClassicFlavorFactory();  MilkTea tea2 = factory2.createMilkTea();  Cup cup2 = factory2.createCup();  tea2.make(); // 输出:制作抹茶拿铁  cup2.show(); // 输出:这是陶瓷杯  // 如果热带风味奶茶店想要推出新口味的奶茶或新风格的杯子,// 只需要在自己的工厂类中添加新的实现  }  
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com