之前本人有一篇文章,在学习模式的时候有实现过一个工厂模式,有实现代码。今天这篇文章又重新对java中的工厂模式有一个完整的理解和学习。
工厂模式的作用
首先工厂模式有什么用呢?当出现聚合情况的时候,A类中有B类的对象作为成员变量,并且B类对象的创建和引用都是在A类中实现的,如果想要使用B类的子类对象的话就必须修改A类中的代码,违反了“开闭原则”。
所以我们引入工厂类,将对象的创建和对象的使用分开。在工厂类中创建对象,在使用类中引入工厂类,这样当被使用的类内部改变时,只用修改工厂类中的代码,而被使用的类的实现方式改变时,我们就可以在使用类中修改。
工厂模式中,我们强调一点:两个类A和B之间的关系应该仅仅是A创建B或者A使用B,而不能两种关系都有。
并且,工厂类可以使得对同一个类的操作都放在同一个类,防止一个类的创建和实例化在好几个类中存在,不好管理,代码重复。
工厂类中还可以提供多个工厂方法,每一个工厂方法对应一个构造函数,客户可以通过使用不同的名字来选择不同的构造函数,而不用只能通过参数的不同去确定使用哪一个构造函数,使用起来更加清晰高效。
以上是个人理解的工厂模式,接下来我们做一个书面一点的总结:
工厂模式的优点有:
- 降低耦合度:
把对象的创建和使用的工程分开; - 降低代码的重复:
如果创建某个对象的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。 - 降低维护成本
由于创建过程都由工厂统一管理,所以发生业务逻辑变化,不需要找到所有需要创建对象B的地方去逐个修正,只需要在工厂里修改即可,降低维护成本。
实现工厂类的三种情况
1.简单工厂类
适用场景:需要创建的对象较少;客户端不需要关心对象的创建过程。
其实就是一个工厂类,一个抽象产品类,一个实现类。
实例
Shape:interface 抽象了一个draw方法。
Circle和Rectangle都实现了Shape类,重写了draw方法;
工厂类的实现其实我们可以直接实现一个getShape方法,通过参数
我们直接利用反射实现工厂类
public class ShapeFactory2 {
public static Object getClass(Class<? extends Shape> clazz) {
Object obj = null;
try {
obj = Class.forName(clazz.getName()).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return obj;
}
}
测试代码:
public class Test2 {
public static void main(String[] args) {
Circle circle = (Circle) ShapeFactory2.getClass(factory_pattern.Circle.class);
circle.draw();
Rectangle rectangle = (Rectangle) ShapeFactory2.getClass(factory_pattern.Rectangle.class);
rectangle.draw();
Square square = (Square) ShapeFactory2.getClass(factory_pattern.Square.class);
square.draw();
}
}
2.工厂方法模式
具体的类由具体的工厂类创建,客户端不知道具体产品类的类名 ,只知道对应的工厂。
一个类需要通过其子类来指定创建哪一个对象,我们只需要指明接口,利用了面向对象的多态性。
实现:
一个工厂接口(有getShape方法),其他相关的工厂都实现该接口,在客户端实现的时候,利用多态,可以实现客户想要的工厂即可:
public class Test {
public static void main(String[] args) {
//工厂
Factory circlefactory = new CircleFactory();
Shape circle = circlefactory.getShape();
circle.draw();
}
}
3.抽象工厂模式
抽象工厂其实就是生产一整套有产品的,这一整套产品一定是有关系或者是有依赖的。区别:工厂方法中的工厂是生产单一产品的。
例如玩游戏时,把枪和子弹分别创建一个工厂接口,AK类和M4A1类实现枪接口,AK子弹类和M4A1子弹类实现子弹接口。Factory工厂类接口中定义两个生产枪和子弹的方法。
public interface Factory {
public Gun produceGun();
public Bullet produceBullet();
}
那么,接下来我们就可以写两个工厂类,均实现自Factory类,分别用于实现AK系列和M4A1系列(包括枪和子弹)
测试:
public class Test {
public static void main(String[] args) {
Factory factory;
Gun gun;
Bullet bullet;
factory =new AK_Factory();
bullet=factory.produceBullet();
bullet.load();
gun=factory.produceGun();
gun.shooting();
}
}