提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
在JAVA设计模式之中,工厂模式是创建型工厂模式的其中一种。我们将会介绍三种工厂模式的简单定义(简单工厂模式,工厂模式,抽象工厂模式),代码来比较各种工厂模式的功能,好处,区别。
其实工厂模式在我们的学习过程中经常会遇见,通俗的讲就是自己种出来的土豆,需要各种麻烦得加工,但是自己懒得做,就把加工的工作交给一家食品加工厂,这个时候你就是工厂的甲方爸爸啦!可怜得帕鲁(打工人)会根据你的要求给你制作土豆泥,薯条等。
提示:以下是本篇文章正文内容,下面案例可供参考
一、工厂模式的分类
首先工厂模式可以分为三类,分别如下
一,简单工厂模式
二,工厂方法模式
三,抽象工厂模式
ps(简单工厂模式,其实并不在GoF23种设计模式之中,但是也可以把简单工厂模式纳入工厂模式的一种。)
二、简单工厂模式
1.看图说话
可以看到图中的Factory是工厂类,它是整个简单工厂模式最重要的一部分,他负责了创建用户所需要的所有对象。Powertato则是抽象的产品角色类,用我上面的理解的话他就是未加工的土豆。其余两个继承了Potato的类就是具体的产品对象了。
// Define the Potato interface
public interface Potato {
// Define methods common to all Potato types here
void prepare();
}
// Define the Chips class
public class Chips implements Potato {
@Override
public void prepare() {
// Implementation specific to Chips
System.out.println("Preparing Chips");
}
}
// Define the PotatoMad class, assuming it's meant to be mashed potatoes
public class PotatoMad implements Potato {
@Override
public void prepare() {
// Implementation specific to Mashed Potatoes
System.out.println("Preparing Mashed Potatoes");
}
}
// Define the PotatoFactory class
public class PotatoFactory {
public static Potato getPotato(String msg) {
if (msg.equals("chips")) {
return new Chips();
} else if (msg.equals("mash")) { // Assuming you meant "mash" instead of "mads"
return new PotatoMad();
} else {
// Throw an exception or return a default implementation
throw new IllegalArgumentException("Unknown Potato type: " + msg);
}
}
}
//运行结果为:
Testing Chips:
this is potato
Testing Chips:
this is potato
Testing Unknown:
Unknown Potato type: unknown
优缺点
优点:
工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。使用者可以免除直接创建产品对象的责任,而仅仅"消费"产品。
客户端无需知道所创建具体产品的类名,只需知道参数即可。
缺点:
工厂类的职责相对过重,增加新的产品时需要修改工厂类的判断逻辑,违背了开闭原则(对扩展开放,对修改关闭)。
不易于扩展过于复杂的产品结构。
简单工厂模式适用于工厂类负责创建的对象较少,客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心的场景。
适用场景
简单工厂模式是一种较为简单和常用的设计模式,它主要用于创建对象的场景中,尤其是当这些对象可以共享一个公共的接口或父类时。尽管它有助于减少系统中直接实例化类的需要,它也有一些限制,比如不太适合应用于复杂对象的创建。以下是简单工厂模式适用的一些具体场景:
-
产品种类相对固定的情况
当一个应用只需要创建某个接口或抽象类的特定几种实现对象时,使用简单工厂模式非常合适。如果产品种类不经常变化,工厂类的改动就会非常少,这样一来,就不会违背开闭原则太多。 -
客户端不需要知道具体产品的类名
简单工厂模式可以让客户端通过一个简单的接口来创建所需的对象,而无需了解这些对象的具体实现类。这种抽象的创建过程有助于减少系统的耦合度,使得代码更加灵活和可维护。 -
创建对象的逻辑相对简单时
如果创建对象的逻辑不是特别复杂,使用简单工厂模式可以使设计更加清晰。对于那些实例化过程比较简单,参数数量不多的产品,简单工厂可以很好地工作。 -
需要集中管理产品创建的场景
当系统中的对象创建需要集中管理和维护时,简单工厂模式提供了一个集中的创建点,帮助避免代码中的重复实例化逻辑,也便于后期的维护和扩展。
不适用场景:
产品种类频繁变化:如果系统经常引入新的产品类型,简单工厂的设计可能会经常改动,这时候使用简单工厂模式可能就不太合适了。
创建逻辑过于复杂:当产品的创建逻辑非常复杂,涉及大量的准备工作或多级检查时,简单工厂的职责会变得过重,不利于维护。
简单工厂模式通过集中处理对象的创建,提高了代码的复用性和封装性,但它也有局限性。因此,在选择是否使用简单工厂模式时,需要根据具体场景和需求谨慎考虑。
工厂方法模式
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个创建对象的接口,但让实现这个接口的类来决定实例化哪一个类。工厂方法让类的实例化推迟到其子类(就是将创建对象的过程放到生产具体类的工厂中去进行,而不是将所有类的创建都放在统一的工厂之中,遵守了开闭原则)。
工厂方法模式主要涉及以下四个角色:
抽象产品(Product):定义工厂方法所创建的对象的接口。
具体产品(ConcreteProduct):实现产品接口的具体类,这些类将由具体工厂来创建。
抽象工厂(Creator):声明工厂方法,该方法返回一个产品类型的对象。创建者也可以定义一个默认的工厂方法的实现,它返回一个默认的具体产品对象。
具体工厂(ConcreteCreator):重写或实现工厂方法以返回一个具体产品实例。
示例类图
代码示例
抽象产品类运动
package com.demo;
public class BasketBall implements Exercise{
@Override
public void exercise() {
System.out.println("这是篮球");
}
}
具体产品类
package com.demo;
public class BasketBall implements Exercise{
@Override
public void exercise() {
System.out.println("这是篮球");
}
}
package com.demo;
public class Soccer implements Exercise{
@Override
public void exercise() {
System.out.println("这是足球");
}
}
package com.demo;
public class VolleyBall implements Exercise{
@Override
public void exercise() {
System.out.println("这是排球");
}
}
抽象工厂类
package com.demo;
public interface ExerciseFactory {
Exercise returnExercise();
}
具体工厂类
package com.demo;
//篮球工厂
public class BasketBallFactory implements ExerciseFactory{
@Override
public Exercise returnExercise() {
return new BasketBall();
}
}
package com.demo;
//足球工厂
public class SoccerFactory implements ExerciseFactory{
@Override
public Exercise returnExercise() {
return new Soccer();
}
}
package com.demo;
//排球工厂
public class VolleyBallFactory implements ExerciseFactory{
@Override
public Exercise returnExercise() {
return new VolleyBall();
}
}
测试类(简写)
package com.demo;
public class Test {
public static void main(String[] args) {
// ExerciseFactory exerciseFactory = null;
// exerciseFactory = new SoccerFactory();
// Exercise exercise = exerciseFactory.returnExercise();
// exercise.exercise(); //返回 这就是足球
ExerciseFactory exerciseFactory = null;
exerciseFactory = new BasketBallFactory();
Exercise exercise = exerciseFactory.returnExercise();
exercise.exercise(); //返回 这就是篮球
}
}
工厂方法模式总结
主要优点
提高了系统的可扩展性:新增一个具体产品类和相应的具体工厂类即可扩展系统,无需修改现有代码,这符合开闭原则。
增强了解耦性:客户代码和具体产品代码之间的耦合度降低,客户代码只需要关心工厂接口而不是具体类的实例化。
单一职责原则:每个具体工厂类只负责创建对应的产品,符合单一职责原则。
主要缺点
可能导致系统中类的数量增加:每增加一个具体产品类,就需要增加一个相应的具体工厂类,使得系统中类的数量成倍增加。
增加了系统的复杂度:系统的复杂度提高,需要更多的时间去理解如何运作,尤其是在有很多产品时。
使用场景
当一个类不知道它所必须创建的对象的类的时候:在工厂方法模式中,具体的产品类名字被具体工厂的实现分离,减少了客户端与具体产品类之间的依赖。
当一个类希望由其子类来指定创建的对象时:工厂方法让类的实例化延迟到其子类进行,用于实现框架或库中的扩展功能。
当类将其创建的对象的生成委托给多个帮助类中的某一个,并且你不知道将会委托给哪个帮助类时:工厂方法将具体类的实例化推迟到其子类中完成,通过工厂方法接口使得类的实例化延迟到子类中进行。
总的来说,工厂方法模式是解决产品创建问题的一种高效且灵活的方式,适合于那些产品类型明确分离,且需要解耦产品的创建过程与使用过程的场景。正确的使用工厂方法模式可以大大提高软件系统的可维护性和扩展性。
抽象工厂方法模式
抽象方法模式其实是工厂模式的泛化,而工厂方法模式又是一种特殊的抽象工厂模式。因为在工厂方法模式种,我们新增一个产品就要增加两个类,当产品增多以后,整个系统会变得及其复杂,大大减小了代码的可读性和可维护性,在抽象工厂方法模式中一个具体工厂可以生产多个具体具体产品。这些具体产品被称为产品族
模式结构
AbstaractFactory抽象工厂
抽象工厂用于声明要生成抽象的方法,在一个抽象工厂种可以定义一组方法,每一个方法来指定一个产品等级结构
ConcreteFactory具体工厂
具体工厂实现了抽象工厂声明抽象产品的方法,生成一组具体产品,这些产品生成了一个产品族,每一个产品都位于某个产品等级结构中,这些产品结构形成了一个产品族
Abstaract抽象产品
为某种产品声明接口,定义抽象方法
Concrete具体产品
定义具体工厂生产的具体产品对象,实现方法
产品族和产品等级结构理解
我们可以假设有三个牌子黄牌子,黑牌子,红牌子还有三种类型的产品方块,圆圈,三角。
那么什么是产品等级结构呢?
产品等级结构在我的理解上就是所有继承了同一种抽象产品的一系列具体产品,比如下图中的将方块抽象成一个抽象,那么黄色,黑色,红色则分别继承了方块抽象,则这三种方块被称为一个产品等级结构。
那么什么是产品族呢??
产品族就是指由同一个工厂产出的,位与不同产品等级结构中的一组产品比如下图中的黄色方块,圆圈,三角这就是一个产品族。重点就是是由同一个工厂生产出来的。
代码解读
场景
在一个电商系统中,商品有不同的种类(如图书、电子产品等),每种商品都有对应的详情页和购物车项。请使用抽象工厂模式设计商品详情页和购物车项的创建过程。
分析
根据场景可以分析得出,产品等级结构是每一种商品,而产品族则是每一种商品页面下的详情功能和购物车功能。根据此来设计抽象工厂。
Abstaract抽象产品
package com.aoyuanhomeword.factory.Details;
//商品详情抽象产品类
public interface Details {
String showDetails();
}
//商品购物车抽象产品类
package com.aoyuanhomeword.factory.ShopCart;
public interface Shopcart {
String openShopcart();
}
Concrete具体产品
//书的详情
package com.aoyuanhomeword.factory.Details;
public class BookDetails implements Details{
@Override
public String showDetails() {
System.out.println("这是书的详情界面");
return "这是书的详情界面";
}
}
//这是电子产品的详情界面
package com.aoyuanhomeword.factory.Details;
public class ElectronicsDetails implements Details{
@Override
public String showDetails() {
System.out.println("这是电子产品的详情界面");
return "这是电子产品的详情界面";
}
}
//这是书的购物车
package com.aoyuanhomeword.factory.ShopCart;
public class Bookcart implements Shopcart {
@Override
public String openShopcart() {
System.out.println("这是书的购物车");
return "这是书的购物车";
}
}
//电子产品的购物车
package com.aoyuanhomeword.factory.ShopCart;
public class ElectronicsCart implements Shopcart{
@Override
public String openShopcart() {
System.out.println("这是电子产品的购物车");
return "这是电子产品的购物车";
}
}
AbstaractFactory抽象工厂
package com.aoyuanhomeword.factory;
import com.aoyuanhomeword.factory.Details.Details;
import com.aoyuanhomeword.factory.ShopCart.Shopcart;
//定义一个抽象工厂,可以看到定义了一个购物车和详情的产品等级结构
public interface MallFactory {
Shopcart shopCartShow();
Details datilsShow();
}
ConcreteFactory具体工厂
package com.aoyuanhomeword.factory;
import com.aoyuanhomeword.factory.Details.BookDetails;
import com.aoyuanhomeword.factory.Details.Details;
import com.aoyuanhomeword.factory.ShopCart.Bookcart;
import com.aoyuanhomeword.factory.ShopCart.Shopcart;
//book工厂继承抽象工程返回一个产品族(书的购物车和详情)
public class BookFactory implements MallFactory{
@Override
public Shopcart shopCartShow() {
return new Bookcart();
}
@Override
public Details datilsShow() {
return new BookDetails();
}
}
package com.aoyuanhomeword.factory;
import com.aoyuanhomeword.factory.Details.Details;
import com.aoyuanhomeword.factory.Details.ElectronicsDetails;
import com.aoyuanhomeword.factory.ShopCart.ElectronicsCart;
import com.aoyuanhomeword.factory.ShopCart.Shopcart;
//电子产品工厂继承抽象工程返回一个产品族(电子产品的购物车和详情)
public class ElectronicFactory implements MallFactory{
@Override
public Shopcart shopCartShow() {
return new ElectronicsCart();
}
@Override
public Details datilsShow() {
return new ElectronicsDetails();
}
}
测试
@Resource
private FacatoryUtil facatoryUtil;
@PostMapping("/book")
public String showBook(@RequestBody FactoryReq request){
String factoryName = request.getFactoryName();
MallFactory factory = facatoryUtil.factoryMap(factoryName);
Shopcart shopcart = factory.shopCartShow();
String s = shopcart.openShopcart();
Details details = factory.datilsShow();
String s1 = details.showDetails();
return s + "\n" + s1;
//当前端调用book接口的时候,后端会根据传来的请求判断使用哪一个工厂,随后
//调用该工厂来创建书购物车和书详情对象,最后返回
//"这是书的购物车"
//”这是书的详情界面“
}
@PostMapping("/eletronic")
public String showElectronic(@RequestBody FactoryReq request){
String factoryName = request.getFactoryName();
MallFactory factory = facatoryUtil.factoryMap(factoryName);
Shopcart shopcart = factory.shopCartShow();
String s = shopcart.openShopcart();
Details details = factory.datilsShow();
String s1 = details.showDetails();
return s + "\n" + s1;
}
}
总结
主要优点
增加新的具体工厂和产品族很方便:抽象工厂模式提供了一个指导方针,便于扩展新的工厂和产品族,而不需要修改现有代码,这有助于系统的扩展和维护。
促进了模块间的解耦:客户端不需要知道它使用的是哪个具体工厂,只需通过抽象接口操作即可,减少了客户端与具体产品之间的依赖。
增强了程序的配置管理功能:可以在应用程序启动时,通过配置文件或环境变量等方式选择具体的工厂实现,从而改变应用程序的行为。
主要缺点
难以支持新种类的产品:如果需要添加新的产品(不是扩展已有产品族),则需要修改抽象工厂及所有具体工厂的接口,这违反了开闭原则。
增加了系统的复杂度:由于引入了多层抽象接口,系统的复杂度增加,有时候也可能增加了系统实现的难度。
使用场景
当需要创建的产品是一系列相互关联或相互依赖的产品族时:抽象工厂模式能够保证客户端始终只使用同一个产品族中的对象。
当一个类库的实现需要被配置或替换时:可以通过抽象工厂来提供不同的实现,进而让客户端根据配置选择不同的实现。
当你要提供一个产品类库,并只想显示它们的接口而不是实现时:抽象工厂模式提供了一种封装一组具有共同主题的产品家族的方法,不需要暴露具体实现。
抽象工厂模式是处理复杂对象创建的有效工具,特别是当这些对象设计到产品族时。它帮助将客户端代码与具体类的实现分离,提高了系统的灵活性和可扩展性。然而,当产品族扩展频繁时,可能会增加系统的复杂性,应当在适合的场景中谨慎使用。