工厂模式
工厂模式属于创建型模式,是java中最常用的设计模式之一,它提供了一种简单、快速、高效、安全的创建对象的方式。使用工厂模式,在接口中定义创建对象的方法,至于如何创建对象则是在接口的实现类中完成,用户如果需要对象实例,只需要通过调用接口方法,而无需知道对象创建的细节。而且还能通过给方法不同的入参得到不同的对象实例,使创建对象的方式更加灵活。
代码实例
用生产手机举个栗子,假设生产的手机有华为和小米。
①定义接口
//生产手机
public interface Phone {
public String getPhone();
}
②定义接口Phone的实现类(两个,一个生产小米手机,一个生产华为手机)
XiaomiPhone
public class XiaomiPhone implements Phone {
@Override
public String getPhone() {
return "生产小米手机";
}
}
HuaWeiPhone
public class HuaWeiPhone implements Phone {
@Override
public String getPhone() {
return "生产华为手机";
}
}
③定义工厂类
public class PhoneFactory {
public Phone creatPhone(String phoneName){
if ("Huawei".equals(phoneName)){
return new HuaWeiPhone();
}else if ("Xiaomi".equals(phoneName)){
return new XiaomiPhone();
}else {
return null;
}
}
}
定义一个工厂类,类里面有个方法creatPhone(),方法有个参数phoneName,通过传入不同的phoneName,生产不同的手机(创建不同的手机对象)。
④使用工厂
public class UseFactory {
public static void main(String[] args) {
PhoneFactory factory = new PhoneFactory();
Phone huaWeiPhone = factory.creatPhone("Huawei");
System.out.println(huaWeiPhone.getPhone());
Phone xiaoMiPhone = factory.creatPhone("Xiaomi");
System.out.println(xiaoMiPhone.getPhone());
}
}
输出
上面,先试用new实例化一个工厂类,然后调用工厂类的有参方法creatPhone,当我们的参数是[Huawei]时,工厂类给我们创将一个HuaWeiPhone 的类的实例并返回,然后调用getPhone()返回“生产华为手机”。同理,当传入的参数是[Xiaomi]时,我们得到的返回结果是“生产小米手机”。
所以,无论我们是想获取小米手机还是华为手机,只需要传入不同的参数即可,工厂模式会帮助我们通过不同的参数创建不同的手机的对象的实例,而且这个过程只需要关注Phone接口中的方法即可,不用关心接口的具体实现。
总结
如上,就是创建一个简单工厂对象,并使用工厂对象,这个时候有人可能会亦或,为什么不能直接用new关键字呢,即需要生产小米手机的时候直接用XiaomiPhone xiaomiPhone = new XiaomiPhone (),需要生产华为手机的时候直接用HuaWeiPhone huaWeiPhone = new HuaWeiPhone (),为什么还是加个工厂来创建,这样不是更麻烦吗?
要解决上面的问题首先得知道这个工厂模式是为了解决什么问题而存在的,我认为工厂模式主要解决了代码的解耦问题、降低了代码的重复,可以代码复用、使程序更加灵活、易维护等问题。
- 解耦
把对象的创建和使用过程分开。加入需要在Class A中想要使用Class B中的方法,这时如果有工厂的存在,就不需要在Class A中进行Class B的实例化了,而是直接关心调用B的那个方法,至于B如何实例化也不用关心,直接交给工厂,自己拿到B实例化后的实例就行了。 - 代码复用、 易维护
想象一个,如果一个对象A的创建过程很复杂,需要很多代码,而且很多地方用到,如果用new,那么就很容易出现相同的代码多次ctrl c,ctrl v的情况。但是如果把创建A的代码交给工厂管理,那么只需要写一次就行了,其他地方如果需要A的实例的话,调用工厂中的方法即可。 - 灵活、易维护
比如上述的例子中有生产小米手机和华为手机两种品牌,现在我们的程序要求都生产小米,并且因为业务需要,在很多类中都用到了XiaomiPhone类的实例,这个时候如果全用的new创建对象,有一天,产品经理说我们不生产小米了,改生产华为,这个时候就需要你非常苦逼得把所有new的地方都找出来改成new HuaweiPhone,工作量很大,但如果用工厂方法创建对象,使用入参[Xiaomi]或者[Huawei]来决定是生产小米手机还是华为手机,把这个入参的值定义在配置文件中或者其他地方,变化时直接改这个参数值即可,改一处,就可以实现由小米到华为的转变。
过了一段时间,产品经理又说,小米和华为都不生产了,生产苹果,这是只需要再写一个Phone的实现类,在工厂方法里再加个判断,入参改为[Apple]即可。
上面就是工厂的优点,但也有缺点,就比如再来个oppo、vivo,那么又需要加新增两个类,这样会使系统中的类的数量一直增加,在一定程度上增加了系统的复杂度。
所以我认为,如果需要创建的对象复杂,或者使用的地方多且有可能需要经常改动对象的创建的时候、又或者需要解耦的时候可以使用工厂模式,如果是简单的对象,也不会有什么改动,可以直接使用new创建。
使用场景
数据库工厂:当还没有定使用什么数据库时,或者数据库有可能会切换时,使用工厂创建数据库实例,可以是Mysql,Oracle等等。
日志记录:可能记录到本地硬盘上、远程机器上等,用户可以选择记录日志到什么地方。
Spring的IOC容器:在Spring中主要提供了两种IOC容器:BeanFactor和ApplicationContext。通过他们来实现对Bean的管理。