JAVA设计模式之工厂模式(简单工厂模式+抽象工厂模式+工厂方法模式)
简单工厂模式(只是让我们容易更理解工厂模式,但本身并不属于23种设计模式中) 为什么有?
从面向对象的角度来看,当我们需要一个对象的时候,我们并不是自己去创建这个对象,而是直接获取一个对象,比如说,我们需要一辆宝马车,我们并不是自己去生产他,而是直接去4S店买一辆就可以了,我们并不需要关心这辆宝马车是怎么生产的,我们只要会开就可以了.这时候我们就需要一个工厂类去为我们初始化这些对象.
核心思想:使我们轻松方便地构造对象实例,而不必关心构造对象实例的细节和复杂过程.
实现:
public class CarFactory {
/**
* 简单工厂模式
*/
public static Car getCar(String carName) {
if(carName == "ford"){
return new FordCar();
}else if(carName == "handa"){
return new HandaCar();
}else if(carName == "benz"){
return new BenzCar();
}else{
return null;
}
}
}
这是最简单的简单工厂模式的实现,但是这有一个很明显的缺点,那就是这种程序太不灵活了.比如说,我现在需要一台宝马车,那我们还需要在工厂中再添加一个if else 的语句,但是修改过后我们还需要重新编译,发布,在部署到服务器中,这显然是十分麻烦的,如果我们需要生产几百种品牌的车,这样写出来的代码将是垃圾的,难以维护的代码,那么我们怎么解决这个问题呢?
答案是通过反射做到灵活的创建对象.
具体代码:
public static Car getCar() throws Exception{
Config config = Config.getInstance();
String carName = config.getProperty("car");
return (Car) Class.forName(carName).newInstance();
}
首先创建一个配置文件,来告诉程序需要建立哪个对象的实例,传入该实例的全路径类名;
car = simplefactory.BenzCar
然后通过读取配置文件,来获得全路径类名并创建对象
properties.load(new FileInputStream(new File("src/simplefactory/car.properties")));
这样我们就可以再不改变任何代码的情况下,通过配置文件来管理汽车工厂里生产的汽车的种类,省去了永无止境的if else判断,也省去了反复的的编译发布部署.使程序的灵活性大大增强,这就是简单工厂模式.
抽象工厂模式
我们再来看刚才的这个例子,发现还是有与我们面向对象编程不符的的情况,哪里呢?
在我们的生活中,不可能会有一家工厂可以生产所有牌子的汽车,福特汽车必须要有福特汽车的工厂进行生产,奔驰汽车也必须由奔驰汽车的工厂来生产,这样,我们原来的的工厂类就变成了一个工厂接口,我们需要由福特工厂奔驰工厂去实现这个工厂类.这样就可以实现通过自家的工厂来生产自家的的汽车了.
那么有人就会问了?我们为什么需要这么麻烦呢?难道就是为了单纯的符合面向对象?符合成活中的例子?就需要分别对每一个类创建一个单独的工厂,难道不知道这样会使我们的代码复杂性大大的增加吗?
当然不是,这样做自然有必须这样做的道理.因为这样可以解决一些仅仅通过简单工厂模式无法解决的问题,
下面我们来看一个问题:
在简单工厂模式中,我们首先获取配置文件中的全路径的类名,在通过全路径的类名来得到他的Class类,最后在根据Class类的newInstance()的方法创建该类的实例对象,这看上去一切仿佛顺理成章,但是不知道大家注意到没有,newInstance()这个方法调用的是该类的无参的构造方法,如果有一个汽车类没有无参的构造方法呢?我们的简单工厂模式是不是就没有办法使用了呢?
又有人会说了,我们不会调用Class的其他的创建实例方法吗?当然可以,但是当你用了其他的方法的时候,你的无参的这个方法是不是就不能用了呢?
所以说,这样就会导致你的这个代码的通用性很差,甚至又回到了最开始那种无限if else的状态,这时候我们就需要使用到我们刚才说的抽象工厂模式来解决.
抽象工厂模式,顾名思义,就是他的工厂是抽象的,可以用来产出各种,各不相同的实例.简单工厂模式只能说是抽象工厂模式的一种特殊情况.
public class FordCar implements Car {
private String color;
public FordCar(String color){
this.color = color;
}
@Override
public void run() {
System.out.println("我是福特轿车.屌丝专属!");
}
}
在这个福特轿车类中,没有默认无参的构造构造方法,所以使用通用的构造方法是无法创建实例对象的,我们必须为其简历单独的工厂..
public class FordCarFactory implements CarFactory {
@Override
public Car getCar() {
return new FordCar("blue");
}
}
在这里,我们为其设置里颜色属性之后就能顺利创建福特车啦.
工厂方法模式
4S店卖轿车,只是生活中的一种情况,在这种境况下,4S店和轿车并不是紧密耦合的关系,4S店只是持有了汽车的一个接口,并没有持有具体的实现类,也就是说他既可以卖福特轿车也可以买奔驰轿车.
大家都知道我们生活中还有一种直营店模式,就是4S店和具体的轿车品牌绑定的,也就是说,我要买福特车只能去福特车的4S店.这在我们的程序中又该如何实现呢?
首先我们需要有一个抽象的4S店类,分别由福特4S店/奔驰4S/本田4S店去继承,4S店有一个售卖轿车的方法;
public abstract class I4S {
public Car sellCar(){
return null;
};
}
这里我们需要返回一个轿车,但是呢,这个抽象的4S点并没有和任何的轿车的工厂相绑定,那我们怎么给他一个轿车返回呢?下面有个很巧妙的解决方法:
public Car sellCar(){
return getCar();
};
public abstract Car getCar();
我们声明了一个抽象的getCar()方法,为父类提供了一个car对象(因为这是一个抽象的的方法,.并没有具体实现,所以实际上,这个car对象是不存在的,仅仅相当于一个占位符罢了),然后我们在具体的子类中实现该方法,为其返回一个子类的对象;
public class HandaCar4S extends I4S {
private HandaCarFactory handaCarFactory;
@Override
public Car getCar() {
return handaCarFactory.getCar();
}
}
这就是工厂方法模式的核心,父类需要的对象有具体的子类来提供;