【设计模式】工厂(Factory)

工厂设计模式属于对象创建型设计模式,通过这种设计模式我们能够快速的创建对象~

在这里插入图片描述

“发消息”时我们可以发邮件、发短信,等等。这里就以发送消息为例子来书写代码。首先设计接口 Sender 。

/**
 * Create by SunnyDay on 2019/03/16
 */
public interface Sender {
    void send();
}

再创建两个实现类 MailSender、 SmsSender

/**
 * Create by SunnyDay on 2019/03/16
 */
public class MailSender implements Sender {
    @Override
    public void send() {
        System.out.println("this is mail sender");
    }
}

/**
 * Create by SunnyDay on 2019/03/16
 */
public class SmsSender implements Sender {
    @Override
    public void send() {
        System.out.println("this is sms sender");
    }
}

一、 普通工厂

普通工厂的设计思想:建立一个工厂类,对外提供公开的方法,根据方法参数来创建对实现统一接口类的对象。

/**
 * Create by SunnyDay on 2019/03/16
 * 普通工厂
 */
public class CommonSendFactory {
    public static final String MAIL_SENDER = "mail";
    public static final String SMS_SENDER = "sms";
    /**
     * @function 创建不同的对象 根据传来的字符串
     * @param type 要创建类型字符串
     * */
    public  Sender produce(String type){
        if (MAIL_SENDER.equals(type)){
            return new MailSender();
        }else if (SMS_SENDER.equals(type)){
            return new SmsSender();
        }else{
            throw new IllegalArgumentException("create object fail, there is no"+type+"object to create!");
        }
    }
}

二、 多个工厂

普通工厂的设计思想:建立一个工厂类,对外提供不同的公开方法,创建不同的接口实现类对象。

/**
 * Create by SunnyDay on 2019/03/16
 */
public class MoreSendFactory {
    /**
     * 创建 MailSender 对象
     */
    public Sender produceMail() {
        return new MailSender();
    }

    /**
     * 创建SmsSender 对象
     */
    public Sender produceSms() {
        return new SmsSender();
    }
}

可见多个工厂是针对普通工厂的改进,普通工厂可能会出现参数误传而导致对应对象创建失败的case。

三、静态工厂

静态工厂的设计思想:基于多个工厂进行修改,把多个工厂的方法加上static 关键字使他们都变成静态方法。这样不需要创建工厂对象就能直接进行对应对象获取。

/**
 * Create by SunnyDay on 2019/03/16
 */
public class StaticSendFactory {
    /**
     * 创建 MailSender 对象
     */
    public static Sender produceMail() {
        return new MailSender();
    }

    /**
     * 创建SmsSender 对象
     */
    public static Sender produceSms() {
        return new SmsSender();
    }
}

四、抽象工厂

抽象工厂其实就是工厂的工厂。负责管理不同的工厂 ???炸一听懵逼😳 且听如下细解~

在这里插入图片描述
普通工厂、多个工厂、静态工厂只能创建同一类产品的不同衍生品,想要创建其他产品就需要重新创建一个约束接口,然后创建接口的实现类。

如何理解呢?

如上Sender可以理解为“辣条”这种产品,而SmsSender、MailSender就是辣条的不同衍生产品如“亲嘴烧辣条”,“麻辣王子辣条”。而此时我想要生产另外一种产品“面包”这样可能吗?至少目前的接口是不支持的,因为目前的接口能够很好的衍生当前的产品,如我再衍生个“卫龙面筋辣条”很简单,只需要以当前的接口为准创建个实现类即可。然而我硬要创建面包就要修改现有接口代码这不可取,违反开闭原则。

那怎样办呢?我们可以新建一个接口然后创建不同的实现类即可:

/**
 * Create by SunnyDay 2022/10/15 11:57:05
 **/
public interface Bread {
    void bread();
}


public class DarkRyeBread implements Bread {
    @Override
    public void bread() {
        System.out.println("DarkRyeBread");
    }
}

public class LightRyeBread implements Bread {
    @Override
    public void bread() {
        System.out.println("LightRyeBread");
    }
}

这样基于上述普通、多个、静态工厂的方式就很容易以工厂方法创建出新的产品了。我们可以仿照前面的写法创建工厂类,这里就以多个工厂为栗子写下:

/**
 * Create by SunnyDay 2022/10/16 13:34:11
 **/
public class MoreBreadFactory {
    public Bread createDarkRyeBread(){
        return new DarkRyeBread();
    }

    public Bread createLightRyeBread(){
        return new LightRyeBread();
    }
}

思考:然而既然都是“产品” 为啥不能再建立一个接口统一约束呢?于是便出现了抽象工厂。直观上看就是 接口管理接口。

这里创建一个新的接口 Provider ,用于管理不同的"产品接口",所有的工厂都需要实现这个接口,以来创建产品。

在这里插入图片描述

/**
 * Create by SunnyDay on 2019/03/16
 */
public interface Provider {
    Sender produceMessage();

    Bread produceBread();
}

产品A ->

/**
 * Create by SunnyDay on 2019/03/16
 * 注意这里对sender工厂进行了变形,若是按照普通、多个、静态工厂的写法,这里需要提供所有sender实现类的实例。
 * 而本类进行了变形,名字定义为具体的工厂类,提供具体的实现类。
 */
public class MailSendFactory implements Provider {


    @Override
    public Sender produceMessage() {
        return new SmsSender();
    }
    // 不是本产品的功能,直接不进行功能处理。
    @Override
    public Bread produceBread() {
        return null;
    }
}
/**
 * Create by SunnyDay on 2019/03/16
 * 注意这里对sender工厂进行了变形,若是按照普通、多个、静态工厂的写法,这里需要提供所有sender实现类的实例。
 * 而本类进行了变形,名字定义为具体的工厂类,提供具体的实现类。
 */
public class SmsSendFactory implements Provider {

    @Override
    public Sender produceMessage() {
        return new MailSender();
    }
    // 不是本产品的功能,直接不进行功能处理。
    @Override
    public Bread produceBread() {
        return null;
    }
}

产品B->

/**
 * Create by SunnyDay 2022/10/15 12:58:23
 * 注意这里对bread工厂进行了变形,若是按照普通、多个、静态工厂的写法,这里需要提供所有bread实现类的实例。
 * 而本类进行了变形,名字定义为具体的工厂类,提供具体的实现类。
 **/
public class DarkRyeBreadFactory implements Provider{
    // 不是本产品的功能,直接不进行功能处理。
    @Override
    public Sender produceMessage() {
        return null;
    }

    @Override
    public Bread produceBread() {
        return new DarkRyeBread();
    }
}
/**
 * Create by SunnyDay 2022/10/15 13:03:00
 * 注意这里对bread工厂进行了变形,若是按照普通、多个、静态工厂的写法,这里需要提供所有bread实现类的实例。
 * 而本类进行了变形,名字定义为具体的工厂类,提供具体的实现类。
 **/
public class LightRyeBreadFactory implements Provider{
    // 不是本产品的功能,直接不进行功能处理。
    @Override
    public Sender produceMessage() {
        return null;
    }

    @Override
    public Bread produceBread() {
        return new LightRyeBread();
    }
}

大功告成,两种产品的工厂类都完事了,接下来测试一下:

public class Test {
    public static void main(String[] args) {
        System.out.println("抽象工厂:");
        // 抽象工厂:以Mail为栗子。
        Provider mailProvider = new MailSendFactory();
        Sender sender = mailProvider.produceMessage();
        sender.send();
        //抽象工厂:以DarkRyeBread为栗子。
        Provider darkRyeProvider = new DarkRyeBreadFactory();
        Bread bread =darkRyeProvider.produceBread();
        bread.bread();
    }
}
/*
log->

抽象工厂:
this is mail sender
DarkRyeBread

可见接口管理接口,所以抽象工厂经历了两次多态~
*/

小结

多个工厂UML类图:

在这里插入图片描述

抽象工厂UML类图:

在这里插入图片描述

抽象工厂设计模式的优点:

  • 封装性:隐藏了对象创建的细节。高层模块无需关心对象的创建的过程。

抽象工厂设计模式的缺点:

  • 拓展困难:产品家族的拓展困难。因为每次创建新的产品,都需要在Provider添加新的方法进行约束,最可恶的是所有工厂类实现这个接口时也要实现新增加的接口方法,然而这个方法对于其他产品是无用的,,,,

其实单类产品的拓展还是挺方便的,如上介绍的我们想要衍生“卫龙面筋辣条”这种产品时,只需为Sender接口派生一个类即可~

The end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值