- 实例化对象,用工厂方法替代new操作,避免你辛苦的准备构造方法的参数
- 工厂模式包括工厂方法模式和抽象工厂模式
- 抽象工厂模式是工厂方法模式的拓展
- 工厂对象可以被传递
工厂模式的意义:
- 在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些情况下, new操作符直接生成对象会带来一些问题。举例来说, 许多类型对象的创造需要一系列的步骤:你可能需要计算或取得对象的初始设置; 选择生成哪个子对象实例; 或在生成你需要的对象之前必须先生成一些辅助功能的对象(即创建对象的过程复杂繁琐)。 在这些情况下,新对象的建立就是一个 “过程”,不仅是一个操作。
- 如果需要客户端来创建对象的话,一旦服务端的该类发生改变(例如本来的构造函数失效了),就会在客户端造成严重的问题,所以我们应该松耦合,把创建对象的过程交给服务端,客户端直接取就可以了。
比喻:
- 还没有工厂时代:假如还没有工业革命,如果一个客户要一款奥迪车,一般的做法是客户去创建一款奥迪车,然后拿来用。
- 简单工厂模式:后来出现工业革命。用户不用去创建奥迪车。因为客户有一个工厂来帮他创建奥迪车.想要什么车,这个工厂就可以建。比如想要A系列车。工厂就创建这个系列的车。即工厂可以创建产品。
- 工厂方法模式:为了满足客户,奥迪车系列越来越多,如A系列,R系列一个工厂无法创建所有的奥迪系列。于是由单独分出来多个具体的工厂。每个具体工厂创建一种系列。即具体工厂类只能创建一个具体产品。但是奥迪工厂还是个抽象。你需要指定某个具体的工厂才能生产车出来。
- 抽象工厂模式:随着客户的要求越来越高,奥迪车必须配置空调。于是这个工厂开始生产奥迪车和需要的空调。
简单工厂模式:
我们先以造奥迪车A系车来举例。首先我们需要先定义一个空的接口类Car和一个接口类Audi_A,且继承了接口类Car,并且声明三个简单的方法
public interface Car {
}
public interface Audi_A extends Car{//显示车辆价格public String luxury();//显示最高车速public String walk();//显示车辆基本参数public String show();}
然后我们创建一个实现Audi_A接口的实体类Audi_A4,类里声明了两个简单的价格,车速属性并且赋值,以及两个构造方法,并且实现接口中的三个方法。
public class Audi_A4 implements Audi_A{接着我们创建一个汽车工厂接口FactoryInterface,声明了三个生产汽车的方法:
private int speed = 180;
private int price = 25;
public Audi_A4() {
System.out.println("这是一辆普通的Audi_A4");
}
public Audi_A4( int speed, int price) {
System.out.println("这是一辆定制版的Audi_A4");
this.speed = speed;
this.price = price;
}
@Override
public String walk() {
// TODO Auto-generated method stub
return "Audi_A4 速度是:" + speed + "km/s";
}
@Override
public String luxury() {
// TODO Auto-generated method stub
return "Audi_A4 的价格是:" + price + "w";
}
@Override
public String show() {
// TODO Auto-generated method stub
return walk() + "\n" + luxury();
}
}
public interface FactoryInterface {接着我们创建一个专门生产奥迪A系的汽车工厂Audi_A_Factory,并且该类实现了工厂接口:
/**
* @方法描述:生产组装标准车
* @创建时间:2017年7月20日下午6:15:34
*/
public Car ProduceCar_original(String id);
/**
* @方法描述:生成经过客户特别定制的车
* @创建时间:2017年7月20日下午6:16:35
*/
public Car ProduceCar_vip(String id,int speed,int price);
/**
* @方法描述:生产经过工厂调整配置的标准车
* @创建时间:2017年7月20日下午6:17:15
*/
public Car ProduceCar_Facotry(String id);
}
public class Audi_A_Factory implements FactoryInterface{下面我们就可以利用工厂类来获得一辆Audi_A4了,但是这个也太容易了,如果这个时候我们需要一辆Audi_A6或者A7,A8呢?我们当然可以在工厂类里面用switch分支语句来选择new其他型号车辆,有没有更好的办法呢?我们可以利用Java的反射机制动态创建对象,我们需要改写Audi_A_Factory类中的ProduceCar_original方法:
/**
* @方法描述:生产组装标准车
* @创建时间:2017年7月20日下午6:15:34
*/
@Override
public Audi_A ProduceCar_original(String id) {
Audi_A audiCar = new Audi_A4();
return audiCar;
}
@Override
public Audi_A ProduceCar_vip(String id, int speed, int price) {
return null;
}
@Override
public Audi_A ProduceCar_Facotry(String id) {
return null;
}
}
@Override此时我们就可以动态生成任何实现了Audi_A接口的奥迪A系车了,我们创建一个叫Audi_A6的类并实现Audi_A接口:
public Audi_A ProduceCar_original(String id) {
try {
Audi_A audiCar = (Audi_A)Class.forName(id).newInstance();
return audiCar;
} catch (ClassNotFoundException | SecurityException |InstantiationException | IllegalAccessException | IllegalArgumentException
e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public class Audi_A6 implements Audi_A{编写一个测试类,并在ProduceCar_original方法中传入Audi_A6的全类名:
private int speed = 200;
private int pirce = 50;
public Audi_A6() {
System.out.println("这是一辆普通的Audi_A6");
}
public Audi_A6(int speed, int pirce) {
System.out.println("这是一辆定制版的Audi_A6");
this.speed = speed;
this.pirce = pirce;
}
@Override
public String walk() {
return "Audi_A6 速度是:" + speed + "km/s";
}
@Override
public String luxury() {
return "Audi_A6 的价格是:" + pirce + "w";
}
@Override
public String show() {
return walk() + "\n" + luxury();
}
}
public class Test {我们可以看到结果打印为:
public static void main(String[] args) {
Audi_A_Factory audiFactory = new Audi_A_Factory();
Audi_A audi_Car = audiFactory.ProduceCar_original("FactoryBean.Audi_A6");
System.out.println(audi_Car.show());
}
}
这是一辆普通的Audi_A6Audi_A6 速度是:200km/sAudi_A6 的价格是:50w通过传入全类名的方式,我们可以利用反射的到类的实例,通过这样的方式我们就可以做到不修改工厂代码就能生产出其他型号的A 系车。
此时我们出现了一个情况因为BMW的装配平台升级,Audi_A4销量下降了,于是我们决定降低Audi_A4的价格,可是我们可能无法直接修改Audi_A4类里的属性,我们需要在工厂中利用构造参数统一调整价格,我们改写Audi_A_Factory类中的ProduceCar_Facotry方法:
@Override随着市场竞争越来越激烈,Audi工厂推出了可以让用户自己指定价格和性能的车,那我们需要改写Audi_A_Factory类中的ProduceCar_vip方法,同样的我们使用反射来生产用户定制的车子(这里注意反射的用法,因为需要传参):
public Audi_A ProduceCar_Facotry(String id) {
Audi_A audi_A;
switch (id) {
case "FactoryBean.Audi_A4":audi_A = new Audi_A4(190,50); break;
case "FactoryBean.Audi_A6":audi_A = new Audi_A6(220, 45); break;
default:audi_A = ProduceCar_original(id); break;
}
return audi_A;
}
@Override我们在测试类中进行测试:
public Audi_A ProduceCar_vip(String id, int speed, int price) {
// TODO Auto-generated method stub
try {
Class<?> cls = Class.forName(id);
Constructor<?> cons = cls.getDeclaredConstructor(int.class,int.class);
cons.setAccessible(true);
Audi_A audiCar = (Audi_A)cons.newInstance(speed,price);
return audiCar;
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException |InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public class Test {可以看到输出为:
public static void main(String[] args) {
Audi_A_Factory audiFactory = new Audi_A_Factory();
Audi_A audi_Car = audiFactory.ProduceCar_vip("FactoryBean.Audi_A6", 300, 200);
System.out.println(audi_Car.show());
}
}
这是一辆定制版的Audi_A6看到这里想必你一定对简单工厂模式有了一个很详细的了解,而工厂方法模式则相当于我们再创建一个工厂类生产Audi的X系车,但是仍然需要实现FactoryInterface即抽象工厂接口,这个时候再看一遍前面工厂模式的意义:
Audi_A6 速度是:300km/s
Audi_A6 的价格是:200w
工厂模式的意义:
- 在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些情况下, new操作符直接生成对象会带来一些问题。举例来说, 许多类型对象的创造需要一系列的步骤: 你可能需要计算或取得对象的初始设置; 选择生成哪个子对象实例; 或在生成你需要的对象之前必须先生成一些辅助功能的对象(即创建对象的过程复杂繁琐)。 在这些情况,新对象的建立就是一个 “过程”,不仅是一个操作。
- 如果需要客户端来创建对象的话,一旦服务端的该类发生改变(例如本来的构造函数失效了),就会在客户端造成严重的问题,所以我们应该松耦合,把创建对象的过程交给服务端,客户端直接取就可以了。