设计模式——抽象工厂

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

抽象工厂

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

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

相关推荐
运维@小兵4 小时前
SpringBoot获取用户信息常见问题(密码屏蔽、驼峰命名和下划线命名的自动转换)
java·spring boot·后端
问道飞鱼5 小时前
【springboot知识】配置方式实现SpringCloudGateway相关功能
java·spring boot·后端·gateway
樽酒ﻬق5 小时前
打造美观 API 文档:Spring Boot + Swagger 实战指南
java·spring boot·后端
ErizJ6 小时前
Golang | 位运算
开发语言·后端·golang·位运算
冼紫菜7 小时前
[特殊字符] Docker 从入门到实战:全流程教程 + 项目部署指南(含镜像加速)
运维·分布式·后端·docker·云原生·容器
秋野酱8 小时前
基于Spring Boot+Vue 网上书城管理系统设计与实现(源码+文档+部署讲解)
vue.js·spring boot·后端
编程毕设9 小时前
【含文档+PPT+源码】基于SpringBoot电脑DIY装机教程网站的设计与实现
java·spring boot·后端
caihuayuan59 小时前
IOS 国际化词条 Python3 脚本
java·大数据·spring boot·后端·课程设计
我的golang之路果然有问题10 小时前
案例速成GO+Socket,个人笔记
开发语言·笔记·后端·websocket·学习·http·golang
boring_11111 小时前
全局id生成器生产方案
大数据·分布式·后端