简单工厂其实不属于23种设计模式之中的,它只是工厂方法的一个相对简易的实现。
优点
- 相对简单
- 不关心对象的具体创建,只要告诉工厂你需要什么即可
缺点
- 违反了开闭原则,在新增需求时还要去修改其内部代码
适用场景
适合需求新增或变更不频繁的业务,例如对接网络运营商,第三方支付公司这种只有几个,可控的范围内的,像英雄联盟这种就不适合了,经过这么多年的发展,已经有100多个英雄了,如果用简单工厂模式,那不得写100多个case或IF分支??
ps:所有的设计模式与软件原则,都是为了增加系统的可维护性与扩展性,在这所有的模式与原则当中,有些是互相违背的,但并不能说它们就是错误的,我们需要从中懂得取舍,而不是生搬硬套,但是请记住,软件工程中最重要的一个原则,就是开闭原则,所有其它的原则都是基于开闭原则衍生出来的
下面我们来设定一个简单的场景,并用简单工厂来实现它:
假设我们的项目中有一个发短信的功能,而我们不同的用户可能用的是不同的手机运营商,例如移动、联通、电信,那我们应该如何去实现不同的手机运营商接收到的是不同的短信内容呢?
首先,我们应该先定义一个接口或者是抽象类,两者在这里的含义是一样的,这里使用的是接口,这个接口只有一个方法,就是发短信的方法
public interface Message {
void send();
}
然后我们去定义一个手机运营商的类并实现Message接口的方法,假设我们现在只对接了移动
public class Yidong implements Message {
@Override
public void send() {
System.out.println("hi,我是移动用户的短信内容");
}
}
然后我们再创建一个message的工厂类:MessageFactory,这个工厂类中有一个静态方法getMessage(),接收一个String类型的参数,然后我们将根据这个参数的值判断将要生产哪个运营商的短信内容给用户
public class MessageFactory {
//注意,这里使用的是静态方法,方法被声明为静态的之后,将失去继承的特性
//子类无法更改父类的静态方法的规则
public static Message getMessage(String name){
switch (name){
case "移动":
return new Yidong();
case "联通":
return new Liantong();
default:
return null;
}
}
}
最后,我们创建一个mian函数来调用这个工厂的静态方法看看
public static void main(String[] args) {
Message message = MessageFactory.getMessage("移动");
message.send();
//最后打印输出的结果为:hi,我是移动用户的短信内容
}
到这里为止,简单工厂就已经完成了,并通过了测试,如果后面有新增的需求,比方说又对接了联通的短信,那么我们只需要新增一个联通的类,并实现Message接口里的方法,然后在MessageFactory中新增一个case分支,在其中new出联通的对象来即可。
在上面的解释可以看出,其实简单工厂它违反了软件设计原则中最重要的一点:开闭原则,一旦我们新增了需求时,我们需要去修改MessageFactory这个类的getMessage方法,所以,这违背了开闭原则。
但也有方法相对的去弥补这种情况:使用反射
public class MessageFactory {
public static Message getMessage(Class clazz){
Message message = null;
try {
message = (Message) Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return video;
}
}
public static void main(String[] args) {
//传入类的class
Message message = MessageFactory.getMessage(Yidong.class);
message.send();
//最后打印输出的结果为:hi,我是移动用户的短信内容
}
这样就可以很显然的看出,我们只需要传入类的class就可以了,内部通过反射去实例化具体的对象的 (对于反射机制有不了解的可以看我博客的另一篇随笔:反射)
使用反射机制来创建具体的实例这种方式就可以避免违反开闭原则,假设我们现在又对接了一个运营商 Dianxin,那么我们只需要传入Dianxin的class就可以获取到Dianxin类的实例了,而不需要去MessageFactory类中去新增case分支或if分支