设计模式——抽象工厂

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

抽象工厂

字面意思:一个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();
    }
}

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

相关推荐
Nejosi_念旧5 小时前
解读 Go 中的 constraints包
后端·golang·go
风无雨5 小时前
GO 启动 简单服务
开发语言·后端·golang
小明的小名叫小明5 小时前
Go从入门到精通(19)-协程(goroutine)与通道(channel)
后端·golang
斯普信专业组5 小时前
Go语言包管理完全指南:从基础到最佳实践
开发语言·后端·golang
一只叫煤球的猫7 小时前
【🤣离谱整活】我写了一篇程序员掉进 Java 异世界的短篇小说
java·后端·程序员
你的人类朋友8 小时前
🫏光速入门cURL
前端·后端·程序员
aramae10 小时前
C++ -- STL -- vector
开发语言·c++·笔记·后端·visual studio
lifallen10 小时前
Paimon 原子提交实现
java·大数据·数据结构·数据库·后端·算法
舒一笑11 小时前
PandaCoder重大产品更新-引入Jenkinsfile文件支持
后端·程序员·intellij idea
PetterHillWater11 小时前
AI编程之CodeBuddy的小试
后端·aigc