简单工厂不是一个标准的设计模式,但是它实在是太常用了,所以需要好好掌握它。要了解简单工程的作用,得先从java程序设计中的接口说起,在java中,接口的思想就是“封装隔离”,这里的封装指的是对被隔离体的行为的封装,而隔离指的是外部调用和内部实现,利用接口将外部调用以及内部实现隔离开来,所以,外部调用是不知道内部具体实现的。那么使用接口具体有什么好处呢,由于外部调用和内部实现被接口隔离开来了,所以只要接口不变,内部实现的变化就不会影响到外部应用,从而使系统变得更加灵活,具有更好的扩展性和可维护性。
那么,在不使用模式的情况下,我们使用接口的步骤是:1.定义接口;2.定义实现类;3.在类中使用接口的实现类。代码如下:
这样使用接口是没错的,但违背了接口封装隔离的思想,从Animal animal = new Cat();这句代码可以清楚的知道了接口以及接口具体的实现,根据接口的思想,实现类Cat是应该被接口Animal封装并隔离开来的,那么,如果为了做到封装隔离,把new Cat()去掉的话,便得不到接口对象,这种情况,我们便可以用简单工厂来解决问题了。
什么是简单工厂呢?简单工厂就是提供一个创建对象实例的功能,而无须关心其具体实现,被创建实例的类型可以是接口、抽象类,也可以是具体的类。
现在,我们可以新建一个Factory类来创建接口,然后将其返回给Test类,这样,在Test类中,便可以直接通过Factory类来获取接口对象了。代码如下:
利用简单工厂,从Test类中无法看出具体的实现是什么,也无法知道是如何实现的。以上的代码只有一个实现类,如果有多个实现类,那么,我们就应该在Factory类中添加选择条件或者选择参数来选择适合条件的类来创建实例对象,所以说,简单工厂方法的内部主要实现的功能是“选择合适的实现类”来创建实例对象。拿上面代码来说,每添加一个实现类,就要多写一行判断代码,并且传入的参数在一定程度上会暴露一些内部的实现细节,代码如下:
新建一个FactoryTest.properties的配置文件并和Factory类放在同一个包下面,配置文件内容如下:
那么,在不使用模式的情况下,我们使用接口的步骤是:1.定义接口;2.定义实现类;3.在类中使用接口的实现类。代码如下:
public interface Animal{
public void run(String s);
}
public class Cat implements Animal{
@Override
public void run(String s){
System.out.println("Cat--->" + s);
}
}
public class Test{
public static void main(String[] args) throws FileNotFoundException, IOException{
Animal animal = new Cat();
animal.run("I can eat");
}
}
这样使用接口是没错的,但违背了接口封装隔离的思想,从Animal animal = new Cat();这句代码可以清楚的知道了接口以及接口具体的实现,根据接口的思想,实现类Cat是应该被接口Animal封装并隔离开来的,那么,如果为了做到封装隔离,把new Cat()去掉的话,便得不到接口对象,这种情况,我们便可以用简单工厂来解决问题了。
什么是简单工厂呢?简单工厂就是提供一个创建对象实例的功能,而无须关心其具体实现,被创建实例的类型可以是接口、抽象类,也可以是具体的类。
现在,我们可以新建一个Factory类来创建接口,然后将其返回给Test类,这样,在Test类中,便可以直接通过Factory类来获取接口对象了。代码如下:
public interface Animal{
public void run(String s);
}
public class Cat implements Animal{
@Override
public void run(String s){
System.out.println("Cat--->" + s);
}
}
public class Factory{
public static Animal createAnimal(){
Animal animal = new Cat();
return animal;
}
}
public class Test{
public static void main(String[] args) throws FileNotFoundException, IOException{
Animal animal = Factory.createAnimal();
animal.run("I can eat");
}
}
利用简单工厂,从Test类中无法看出具体的实现是什么,也无法知道是如何实现的。以上的代码只有一个实现类,如果有多个实现类,那么,我们就应该在Factory类中添加选择条件或者选择参数来选择适合条件的类来创建实例对象,所以说,简单工厂方法的内部主要实现的功能是“选择合适的实现类”来创建实例对象。拿上面代码来说,每添加一个实现类,就要多写一行判断代码,并且传入的参数在一定程度上会暴露一些内部的实现细节,代码如下:
public interface Animal{
public void run(String s);
}
public class Cat implements Animal{
@Override
public void run(String s){
System.out.println("Cat--->" + s);
}
}
public class Dog implements Animal{
@Override
public void run(String s){
System.out.println("Dog--->" + s);
}
}
public class Factory{
public static Animal createAnimal(int tag){
if(tag == 1){
Animal animal = new Cat();
}else if(tag == 2){
Animal animal = new Dog();
}
return animal;
}
}
public class Test{
public static void main(String[] args) throws FileNotFoundException, IOException{
Animal animal = Factory.createAnimal(1);
animal.run("I can eat");
}
}
每次添加实现类后就要修改Factory类的代码,这显然是不合适的,所以,我们可以使用Properties配置文件以及使用反射机制来进行完善。代码如下:
public interface Animal{
public void run(String s);
}
public class Cat implements Animal{
@Override
public void run(String s){
System.out.println("Cat--->" + s);
}
}
public class Dog implements Animal{
@Override
public void run(String s) {
// TODO Auto-generated method stub
System.out.println("Dog--->" + s);
}
}
public class InitProperties {
public static Properties getPro() throws FileNotFoundException, IOException{
Properties p = new Properties();
InputStream in = null;
try{
in = Factory.class.getResourceAsStream("FactoryTest.properties");
p.load(in);
}catch(IOException e){
System.out.println("装载工厂配置文件出错");
e.printStackTrace();
}finally{
try{
in.close();
}catch(IOException e){
e.printStackTrace();
}
}
return p;
}
}
public class Factory{
public static Animal createAnimal(String className){
Animal animal = null;
try {
animal = (Animal)Class.forName(className).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return animal;
}
}
public class Test{
public static void main(String[] args) throws FileNotFoundException, IOException{
Properties p = InitProperties.getPro();
Animal animal = Factory.createAnimal(p.getProperty("DogClass"));
if(animal != null){
animal.run("I can eat");
}
}
}
新建一个FactoryTest.properties的配置文件并和Factory类放在同一个包下面,配置文件内容如下:
CatClass=com.beiji.simplefactory.Cat //=后面是包名+类名
DogClass=com.beiji.simplefactory.Dog