设计模式——抽象工厂

设计模式专栏第二弹,抽象工厂

抽象工厂

字面意思:一个xx工厂,可以是水果工厂,化肥工厂,江南皮革厂...跑题了,那么为什么叫做抽象呢,后续带你慢慢揭开抽象的面纱。

先上定义:抽象工厂模式是一种创建型设计模式, 它能创建一系列相关的对象, 而无需指定其具体类。

问题抛出

假设你正在开发宠物商店项目。可能里面牵扯很多种动物,比如:狗,猫...,狗呢又有很多分类,比如:黑的,白的,牧羊犬... 这时候你需要单独的生成每种类型动物对应的对象,这样才能保证其正确性。同时呢,我们也不想添加新产品时修改已有代码,要不然以后每次添加新类型的动物,岂不是都要改动原有的代码。

解决方法:

首先, 抽象工厂模式建议为系列中的每件产品明确声明接口 (例如狗、 猫)。 然后, 确保所有产品变体都继承这些接口。 例如, 所有类型的狗都实现 接口; 所有类型的猫都实现 接口, 以此类推。

如下类图所示(忽略画图太丑~ ~):各种类型的狗都来实现这个接口。

WhiteDog

java 复制代码
public class WhiteDog implements IDog{
    @Override
    public void eat() {
        System.out.println("我是 WhiteDog ~~~");
    }
}

BlackDog

typescript 复制代码
public class BlackDog implements IDog{
    @Override
    public void eat() {
        System.out.println("我是 BlackDog~~~~");
    }
}

实现ICat的,就省略了,跟实现IDog相同,名称换一下即可

此时我们就想了,能不能有一个东西(工厂),不管是什么类型的动物,例如:猫,狗,我们只需要调用抽象接口,就能返回给我们的是白猫或者是白狗。此时就引出抽象工厂了------包含系列中所有产品构造方法的接口。例如:createCatcreateDog。这些方法必须返回抽象 产品类型, 即我们之前抽取的那些接口:IDogICat。如下代码所示:

java 复制代码
public interface IAnimalFactory {
    /**
     * 定义创建Icat接口实例的方法
     */
    ICat createCat();
    /**
     * 定义创建IDog接口实例的方法
     */
    IDog createDog();
}

此时有的小伙伴就说了,那我现在调用了createCat()能给我一个白猫嘛,目前当然不能啦,接着往下看。

此时我们已经有了抽象工厂了,你可以想象成这是一个动物世界包含任意一种类型的动物。那么该如何处理动物的变体呢(也就是我们需要特殊的,比如猫类中的白猫呢)? 对于系列产品的每个变体, 我们都将基于 抽象工厂(IAnimalFactory)接口创建不同的工厂类。 每个工厂类都只能返回特定类别的产品。如下代码:

java 复制代码
// 变体的工厂,都需要实现抽象工厂
public class WhiteAnimalFactory implements IAnimalFactory {
    public ICat createCat() {
        // 返回的是具体的实现类,并非抽象的
        return new WhiteCat();
    }
    public IDog createDog() {
        return new WhiteDog();
    }
}

也就只能创建出WhiteCatWhiteDog

java 复制代码
public class BlackAnimalFactory implements IAnimalFactory {
    public ICat createCat() {
        return new BlackCat();
    }
    public IDog createDog() {
        return new BlackDog();
    }
}

让我们来测试一下吧

假设客户端想要工厂创建一个Dog。 客户端无需了解工厂类, 也不用管工厂类创建出的Dog类型。 无论是白色, 还是黑色Dog, 对于客户端来说没有分别, 它只需调用抽象 IDog接口就可以了。 这样一来, 客户端只需知道Dog以某种方式实现了 eat方法就足够了。 此外, 无论工厂返回的是何种Dog变体, 它都会和由同一工厂对象创建的Cat风格或者是颜色一致。如下代码所示:

ini 复制代码
public class Test {
   public static void main(String[] args) {
       // 创建了一个BlackAnimalFactory工厂
       IAnimalFactory blackAnimalFactory = new BlackAnimalFactory();
       ICat blackCat = blackAnimalFactory.createCat();
       // 此时调用的是具体实现了ICat的BlackCat中的eat方法
       blackCat.eat();

       IDog blackDog = blackAnimalFactory.createDog();
       blackDog.eat();
       
       IAnimalFactory whiteAnimalFactory = new WhiteAnimalFactory();
       ICat whiteCat = whiteAnimalFactory.createCat();
       whiteCat.eat();
       IDog whiteDog = whiteAnimalFactory.createDog();
       whiteDog.eat();
   }
}

如果小伙伴们看上面的代码有点绕不太理解,可以去看看面向接口编程的帖子,来了解为什么可以这样书写。

日常提问: 小伙伴们可以讨论在spring中哪些使用到了抽象工厂吗?欢迎评论讨论学习~~

附加问题:小伙伴们看看如下代码,在没有执行测试类,大家能看出来会有什么问题吗?为什么会这样呢?

java 复制代码
public class Father {
    public Father() {
        start();
    }
    protected void start() {}
}
java 复制代码
public class Child extends Father {
    private Integer i;
 
    public Child() {
        i = 1;
        start();
    }
 
    @Override 
    public void start() {
        System.out.println(i.byteValue());
    }
}
typescript 复制代码
public class TestF {
    public static void main(String[] args) {
        Child child = new Child();
        child.start();
    }
}

今日划水结束,准备下班喽~~~~

相关推荐
桦说编程2 小时前
深入解析CompletableFuture源码实现(2)———双源输入
java·后端·源码
舒一笑2 小时前
大模型时代的程序员成长悖论:如何在AI辅助下不失去竞争力
后端·程序员·掘金技术征文
lang201509282 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
小羊在睡觉3 小时前
golang定时器
开发语言·后端·golang
用户21411832636023 小时前
手把手教你在魔搭跑通 DeepSeek-OCR!光学压缩 + MoE 解码,97% 精度还省 10-20 倍 token
后端
追逐时光者3 小时前
一个基于 .NET 开源、功能强大的分布式微服务开发框架
后端·.net
刘一说4 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端
壹佰大多4 小时前
【spring如何扫描一个路径下被注解修饰的类】
java·后端·spring
间彧4 小时前
Java双亲委派模型的具体实现原理是什么?
后端
间彧4 小时前
Java类的加载过程
后端