工厂设计模式属于对象创建型设计模式,通过这种设计模式我们能够快速的创建对象~
“发消息”时我们可以发邮件、发短信,等等。这里就以发送消息为例子来书写代码。首先设计接口 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接口派生一个类即可~