工厂模式是一种设计思想,它适用于需要创建多个具体实例的场景,并且这些实例都具有一个共同的方法(动作)。比如,“发送信息”。我们都知道,发送信息的方式有很多种,但无论是用微信发送,还是用邮件发送,它们都有一个共同的动作,就是“发送”,那么可以把这个动作(send)抽象出来。
1.普通工厂模式
抽象的动作:
package com.itant.pattern.sender;
public interface Sender {
void send();
}
具体的实现:
package com.itant.pattern.sender;
public class EmailSender implements Sender {
@Override
public void send() {
System.out.println("用邮件发送");
}
}
package com.itant.pattern.sender;
public class WechatSender implements Sender {
@Override
public void send() {
System.out.println("用微信发送");
}
}
经过以上的步骤,发送的动作有了,还差一个“工厂”来生成这些具体的发送动作:
package com.itant.pattern;
import com.itant.pattern.sender.EmailSender;
import com.itant.pattern.sender.Sender;
import com.itant.pattern.sender.WechatSender;
public class CommonFactory {
public Sender generateSender(String type) {
if (type.equals("email")) {
return new EmailSender();
} else if (type.equals("wechat")) {
return new WechatSender();
} else {
return null;
}
}
}
测试:
package com.itant.pattern;
import com.itant.pattern.sender.Sender;
public class Test {
public static void main(String[] args) {
// 普通工厂模式
CommonFactory commonFactory = new CommonFactory();
Sender wechatSender = commonFactory.generateSender("wechat");
wechatSender.send();
Sender emailSender = commonFactory.generateSender("email");
emailSender.send();
}
}
2.多个工厂方法模式
以上的普通工厂模式有个缺点,就是参数传错了的话,可能返回的Sender会为null,引起空指针异常等情况,虽然可以做一些判断去“补救”,但这样的设计是有缺陷的,不建议在设计的时候用,要想规避这种情况,那么我们就不要传参了,直接使用指定的方法生成指定的Sender即可,我们改造一下Factory:
package com.itant.pattern;
import com.itant.pattern.sender.EmailSender;
import com.itant.pattern.sender.Sender;
import com.itant.pattern.sender.WechatSender;
public class MultiFactory {
public Sender generateWechatSender() {
return new WechatSender();
}
public Sender generateEmailSender() {
return new EmailSender();
}
}
测试:
package com.itant.pattern;
import com.itant.pattern.sender.Sender;
public class Test {
public static void main(String[] args) {
MultiFactory multiFactory = new MultiFactory();
Sender wechatSender = multiFactory.generateWechatSender();
wechatSender.send();
Sender emailSender = multiFactory.generateEmailSender();
emailSender.send();
}
}
这样确实是可以避免参数传错的情况了,但我们可以进一步优化,在多个工厂方法模式的基础上进行优化,于是引入静态工厂模式。
3.静态工厂模式
同样是改造Factory,在多个工厂方法模式的基础上,把方法改成static的,这样就可以省略实例化工厂的步骤:
package com.itant.pattern;
import com.itant.pattern.sender.EmailSender;
import com.itant.pattern.sender.Sender;
import com.itant.pattern.sender.WechatSender;
public class StaticFactory {
public static Sender generateWechatSender() {
return new WechatSender();
}
public static Sender generateEmailSender() {
return new EmailSender();
}
}
测试:
package com.itant.pattern;
import com.itant.pattern.sender.Sender;
public class Test {
public static void main(String[] args) {
Sender wechatSender = StaticFactory.generateWechatSender();
wechatSender.send();
Sender emailSender = StaticFactory.generateEmailSender();
emailSender.send();
}
}
好的,目前为止,似乎一切还不错,大多数情况下,使用静态工厂模式即可,因为它确实是满足开发需求的,而且也比较简洁清晰。但是有一个问题就是,每次有新的实例都要修改我们的工厂类,例如有一天,新增了一个发送方式–“QQSender”,这个时候,我们必然要修改StaticFactory,新增一个generateQQSender()的方法,这样是违背了设计模式的“开闭原则”的,即:我们希望对扩展开放,对修改关闭。于是引入终极的抽象工厂模式:
4.抽象工厂模式
抽象工厂模式同样是对工厂进行改造。最开始的时候,我们就对“发送”这个动作进行了抽象,举一反三,我们同样也可以对工厂频繁“生产”这个动作进行抽象:
package com.itant.pattern.factory;
import com.itant.pattern.sender.Sender;
public interface Factory {
Sender generateSender();
}
然后我们需要什么样具体的工厂的话就可以自行扩展:
package com.itant.pattern.factory;
import com.itant.pattern.sender.Sender;
import com.itant.pattern.sender.WechatSender;
public class WechatFactory implements Factory {
@Override
public Sender generateSender() {
// TODO Auto-generated method stub
return new WechatSender();
}
}
package com.itant.pattern.factory;
import com.itant.pattern.sender.EmailSender;
import com.itant.pattern.sender.Sender;
public class EmailFactory implements Factory {
@Override
public Sender generateSender() {
// TODO Auto-generated method stub
return new EmailSender();
}
}
测试:
package com.itant.pattern;
import com.itant.pattern.factory.EmailFactory;
import com.itant.pattern.factory.Factory;
import com.itant.pattern.factory.WechatFactory;
import com.itant.pattern.sender.Sender;
public class Test {
public static void main(String[] args) {
Factory wechatFactory = new WechatFactory();
Sender wechatSender = wechatFactory.generateSender();
wechatSender.send();
Factory emailFactory = new EmailFactory();
Sender emailSender = emailFactory.generateSender();
emailSender.send();
}
}
这样,我们就得到了相对比较完整的工厂模式。抽象工厂模式适用于某种动作有多种实现方式(某种操作有多种实现方案)的情况,扩展方便、灵活,如果非要说缺点,就是工厂类的增加,每新增一种操作,都需要新增一个对应的工厂类,在简单的项目中似乎显得冗余,但是在复杂的项目中则可以让条理非常清晰,所以,在实际使用过程中,可以针对项目的复杂情况而采用相应的工厂模式,在简单的小项目中,可以直接使用静态工厂模式,在复杂的项目中,推荐使用抽象工厂模式。