是设计模式,我们有救了!!!(二、工厂模式)

github.com/YaYiXiBa/Ja... 欢迎去看我的代码哦。。。


highlight: a11y-dark

1. 简单工厂模式 (Simple Factory)

优点:

  • ​实现简单​:结构简单,易于理解和实现

缺点:

  • ​违反开闭原则​:增加新产品需要修改工厂类逻辑
  • ​职责过重​:工厂类集中了所有产品的创建逻辑
  • ​扩展性差​:当产品类型较多时,工厂方法会变得臃肿 首先,先尝试实现以下类图:
typescript 复制代码
//工厂类
public class SimpleFactory {
    public static Shape getShape(String shapeType) {
        if (shapeType.equalsIgnoreCase("Square")) {
            return new Square();
        }else if (shapeType.equalsIgnoreCase("Circle")) {
            return new Circle();
        }else if (shapeType.equalsIgnoreCase("Triangle")) {
            return new Trangle();
        }else{
            return null;
        }
    }
}
//客户端
public class Client {
    public static void main(String[] args) {
        Shape square = SimpleFactory.getShape("Square");
        assert square != null;
        square.draw();
    }
}
//运行结果
Drawing Square

Process finished with exit code 0

简单工厂模式存在,却又经常被说是不算严格的设计模式。为什么呢? 看一下类图:我们就是将手动new对象的方法进行了封装,把他们都放在了一个类中,作为静态方法getShape(String shapeType) 来调用。所以说,他简单。同时也带来了前文所述的缺点。

2. 工厂方法模式 (Factory Method)

先看图,其实可以去自己尝试实现一下。

这是一个使用手机工厂和电脑工厂实现生产产品的例子。很形象,但是建议注意细节:

  1. Product是所有产品类都要实现的接口,里面有一个展示功能的方法showFunction()。如此一来,任何工厂产出的物品就得到了统一,不管是生产手机,还是生产电脑,都可以返回Product。
  2. 手机工厂里的生产步骤是new Phone(),电脑工厂是new PC()。Phone和PC都实现了Product接口,都可以作为Product返回。
  3. 既然所有工厂都是在生产Product,不妨就把createProduct方法抽象出来,放在Factory接口中,要求所有的实际工厂都要实现这个接口。

先贴出部分代码,后续会给出github链接:

java 复制代码
public interface Product {
    public void showFunction();
}

public interface Factory {
    public Product createProduct();
}


public class PCFactory implements Factory{
    @Override
    public Product createProduct() {
        return new PersonalComputer();
    }
}


public class Phone implements Product{
    @Override
    public void showFunction() {
        System.out.println("手机可以打电话");
    }
}

public class Client {
    public static void main(String[] args) {
        Factory pcFactory = new PCFactory();
        Product pc = pcFactory.createProduct();
        pc.showFunction();

        PhoneFactory phoneFactory = new PhoneFactory();
        Product phone = phoneFactory.createProduct();
        phone.showFunction();
    }
}

优点:

  • ​符合开闭原则​:增加新产品只需添加新的工厂子类,无需修改现有代码
  • ​单一职责原则​:每个具体工厂只负责创建一种产品
  • ​灵活性高​:可以形成基于继承的等级结构
  • ​解耦彻底​:客户端只需要知道抽象工厂和抽象产品

缺点:

  • ​类数量增加​:每增加一个产品就需要增加一个具体工厂类
  • ​复杂性增加​:引入了抽象层,增加了系统的抽象性和理解难度
  • ​需要额外开销​:需要编写更多的类和接口

3. 抽象工厂模式 (Abstract Factory)

如果你彻底理解了工厂模式,那么抽象工厂很容易理解了。重点在于"抽象"二字。先看一下类图(哎,自己电脑装的是社区版生成不了diagram凑合看下吧。。。)

给出几个factory的代码,带着问题看:

  1. 创建产品的方式:public Color getColor(String colorName)、public Product getProduct(String productName)。Color和Product都是产品。这不是又回到了简单工厂的方式吗?在方法工厂中我们是使用单独的工厂来创建单独的产品。但抽象工厂面向的场景是,生产一组具有相互依赖关系的产品。比如各种"颜色"和各种电子产品。"红色"的"手机"和"黑色"的"手表",我们将其视为两组产品,他们之间是具有绑定关系的产品。试想,现在我现在就要生产"红色"的"手机"和"黑色"的"手表"。如果按照工厂方法的方式,在客户端,是不是要new四个工厂,分别生产四种对象。所以在这种场景下,如果将"电子设备"和"颜色"独立开,让ColorFactory和ProductFactory分别负责一类产品的生产,在客户端的操作就更方便一些。
  2. 关于"抽象":现在两个工厂的职责已经分开了,但是在客户端(也就是图中的AbstractFactoryParttenDemo,代码里我直接写的Client)与实际工厂之间仍然加了一层抽象,也就是抽象工厂。这里的目的在于让客户端代码只依赖抽象接口,让"解耦"更加彻底。这样即使工厂在创建产品的过程中发生了步骤上的变化,客户端的代码也不需要改动,因为引入的只是工厂实现类的上层抽象。注意看客户端的两行代码:

Factory colorFactory = FactoryProducer.getFactory("ColorFactory");

Factory productFactory = FactoryProducer.getFactory("ProductFactory");在客户端看来,管你是什么工厂实现类,我都按照Factory类来接受,然后给你一个局部变量则我这边做个标识就可以了。这样哪怕你有一天不叫ColorFactory了,改成"ColorMakeFactory"或者换了别的工厂来生产某个产品都无所谓。

3.为什么还有FactoryProducer:这里的逻辑其实就是在根据名称返回具体的实现类对吧? "名称"是客户端传来的,那么new出实际的工厂应该是谁来负责呢?肯定不能交给客户端吧。当然是属于我们提供给客户端的入口。客户端只需要调用FactoryProducer的getFactory方法就可以到到想要的工厂,这就叫做"无需关心具体的实现"。

csharp 复制代码
public abstract class  Factory {
    public abstract Product getProduct(String productName);
    public abstract Color getColor(String colorName);
}
scala 复制代码
public class ColorFactory extends Factory{
    @Override
    public Product getProduct(String productName) {

        return null;
    }

    @Override
    public Color getColor(String colorName) {
        if(Objects.equals(colorName, "red")){
            return new Red();
        }else if(colorName.equals("black")){
            return new Black();
        }else if (colorName.equals("yellow")){
            return new Yellow();
        }
        return null;
    }
}
scala 复制代码
public class ProductFactory extends Factory{
    @Override
    public Product getProduct(String productName) {
        if(productName.equals("PC")){
            return new PC();
        }else if(productName.equals("Phone")){
            return new Phone();
        }else if(productName.equals("Watch")){
            return new Watch();
        }
        return null;
    }

    @Override
    public Color getColor(String colorName) {
        return null;
    }
}
csharp 复制代码
public class FactoryProducer {
    public static Factory getFactory(String factoryName){
        if(factoryName.equals("ColorFactory")){
            return new ColorFactory();
        } else if (factoryName.equals("ProductFactory")) {
            return new ProductFactory();
        }else{
            throw new RuntimeException("名称有误");
        }
    }
}
ini 复制代码
public class Client {
    public static void main(String[] args) {
        Factory colorFactory = FactoryProducer.getFactory("ColorFactory");
        Factory productFactory = FactoryProducer.getFactory("ProductFactory");
        Color red = colorFactory.getColor("red");
        Product watch = productFactory.getProduct("Watch");
        red.showColor();
        watch.showFunction();

        Color yellow = colorFactory.getColor("yellow");
        Product phone = productFactory.getProduct("Phone");
        yellow.showColor();
        phone.showFunction();
    }
}
运行结果:
红色
手表可以装*
黄色
手机可以打电话

Process finished with exit code 0

优点:

  • ​产品族支持​:能创建一组相关或依赖的对象
  • ​一致性保证​:保证客户端始终只使用同一个产品族中的对象
  • ​开闭原则​:易于扩展产品族,增加新的产品族很方便
  • ​解耦彻底​:客户端与具体类实现分离

缺点:

  • ​扩展产品等级困难​:增加新产品需要修改抽象工厂接口及所有具体工厂类
  • ​类数量激增​:支持的产品族和产品等级越多,系统越复杂
  • ​设计复杂​:需要精心设计接口,否则难以应对变化

对比总结

模式 创建对象方式 扩展新产品 扩展新产品族 适用场景
简单工厂 集中创建 修改工厂类 不支持 对象较少,变化不大
工厂方法 子类创建 添加子类 不支持 单一产品,需要灵活扩展
抽象工厂 产品族创建 修改接口 添加子类 相关产品族,强调一致性

​​选择建议​​:

  • 当产品类型较少且不经常变化时,使用简单工厂
  • 当需要灵活创建单一产品时,使用工厂方法
  • 当需要创建一组相关产品时,使用抽象工厂 github.com/YaYiXiBa/Ja... 欢迎去看我的代码哦。。。
相关推荐
金銀銅鐵10 小时前
[Java] 用 GUI 展示 EnumSet 增减元素时的内部变化(上)
java·后端·ai编程
念何架构之路10 小时前
go-grpc设计思想
开发语言·后端·golang
system_error_x11 小时前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
步行cgn13 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
码事漫谈13 小时前
AI 读你的提示词,其实很没耐心
后端
用户83562907805114 小时前
如何使用 Python 格式化 Excel 单元格中的长文本
后端·python
我命由我1234514 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
IT_陈寒14 小时前
Java性能优化完全指南
前端·人工智能·后端
电子IT笔记14 小时前
对接群晖NAS,上传和删除踩坑记录
前端·后端
Mk5987814 小时前
P4:把 Agent 的记忆搬进 Redis —— AgentScope-Java 工程化实战
后端