众所周知,在我们的现实生活中,工厂是用来生成产品的,而且产品有一种或多种,它们的特征可能相同,也可能只是部分相同。但不管如何,我认为在工厂模式中,需要理解好两个关键的角色就是:工厂与产品。
工厂模式分为简单工厂、工厂和抽象工厂三种,它是创建型设计模式。(创建型模式提供了一种在创建对象的同时,隐藏创建逻辑的方式,而不是使用new运算符直接实例化对象。这样的话在针对某个给定实例需要创建哪些对象时就可以更加灵活的选择了)
简单工厂模式就是由一个工厂类根据传入的参数决定创建哪一种的产品类。它们之间的关系如下:
简单工厂模式实例:
//动物接口
interface Animal{
public void speak();
}
//人实现类
class Man implements Animal{
@Override
public void speak() {
System.out.println("我是人我会说话:哈哈哈!!!");
}
}
//狗实现类
class Dog implements Animal{
@Override
public void speak() {
System.out.println("我是小狗不会说话:汪汪汪!!!");
}
}
//工厂类
class Factory{
public Animal getAnimal(String name){
if("man".equals(name)){
return new Man();
}else{
return new Dog();
}
}
}
//测试类
public class GeneralFactory {
public static void main(String[] args){
Factory factory = new Factory();
Animal an = factory.getAnimal("dog");
an.speak();
}
}
上面代码中,定义了一个动物(Animal)接口,接着分别定义了人(Man)和狗(Dog)实现类,让后用一个工厂类(Foctory)去“生成”他们。
如果我们现在不用工厂模式,在调用人的说话方法时需要new一个人(Man)的对象,使用狗的说话方式时,需要new一个狗(Dog)类的对象。这样在new对象时,就需要考虑到接口和子类的实现方式,增加了代码的耦合度。
使用简单工厂模式时封装一个工厂类,把new对象的操作放在这个工厂类中,这样我们在调用子类里面的方法时,并不需要关心子类的实现方式,只需要调用工厂类,让工厂类给我们实现new对象的过程。比如我需要工厂给我生产一件衣服或一双鞋子时,我并不关心衣服或鞋子用了什么布料百分之几的聚脂钎维百分之几棉绒等等啥的,也不必要去知道它经过了哪几道程序生产出来的,只要你把最终我想要的衣服做出了就好了。 也可以看出这样最大的好处当然就是面向对象编程思想中要尽量降低了代码之间的耦合度,不需要你关心的事情就不必care。
但是简单工厂模式有个很大的弊端,就是现在要实现很多动物的speak()方法,那么工厂类里面就要不断的添加new对象的操作,很显然这样还是要修改工厂类中的代码极其不好。但我们还有绝招,那就是使用Java的反射机制来解决。
采用反射机制的简单工厂模式实例:
package comfactory;
//动物接口
interface Animal1{
public void speak();
}
//人实现类
class Man1 implements Animal{
@Override
public void speak() {
System.out.println("我是人我会说话:哈哈哈!!!");
}
}
//狗实现类
class Dog1 implements Animal{
@Override
public void speak() {
System.out.println("我是小狗不会说话:汪汪汪!!!");
}
}
//工厂类
class Factory1{
public Object getAnimal(String className) throws Exception{
Class<?> cls = Class.forName(className);
Object obj = cls.newInstance();
return obj;
}
}
//测试类
public class ReflectFactory {
public static void main(String[] args) throws Exception{
Factory1 factory = new Factory1();
Animal an = (Animal)factory.getAnimal("com.factory.Man1");
an.speak();
}
}
采用反射后,无论添加多少个子类,工厂类中的代码都不需要修改,只需要在操作的时候传入子类的类路径(包名+类名)就可以了,实现了各个业务逻辑之间的完全分离,很好的降低了代码的耦合性。
使用反射机制实现的工厂模式可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。
使用反射机制并结合属性文件的工厂模式(即Spring中的IOC)实例:
首先创建一个animal.properties的资源文件:
man=com.factory.Man
dog=com.factory.Dog
package com.factory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
//动物接口
interface Animal {
public void speak();
}
// 人实现类
class Man implements Animal {
@Override
public void speak() {
System.out.println("我是人我会说话:哈哈哈!!!");
}
}
// 狗实现类
class Dog implements Animal {
@Override
public void speak() {
System.out.println("我是小狗不会说话:汪汪汪!!!");
}
}
// 操作属性文件类
class init {
public static Properties getPro() throws FileNotFoundException, IOException {
Properties pro = new Properties();
//注意:这里文件名要与接口名一致才能映射上
File f = new File("Animal.properties");
if (f.exists()) {
pro.load(new FileInputStream(f));
} else {
pro.setProperty("man", "com.factory.Man");
pro.setProperty("dog", "com.factory.Dog");
pro.store(new FileOutputStream(f), "ANIMAL CLASS");
}
return pro;
}
}
// 工厂类
class Factory {
public static Animal getAnimal(String className) throws Exception {
Animal a = (Animal)Class.forName(className).newInstance();
return a;
}
}
// 测试类
class ReflectFactory {
public static void main(String[] args) throws Exception {
Properties pro = init.getPro();
Animal an = Factory.getAnimal(pro.getProperty("man"));
if (an != null) {
an.speak();
}
}
}
IOC中最基本的技术就是“反射(Reflection)”,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象,这种编程方式可以让对象在生成时才被决定到底是哪一种对象。其实我们可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言提供的反射机制,根据配置文件中给出的类名生成相应的对象。这就是IOC的实现原理--反射机制在工厂模式中的应用。