在Java语言中,我们通常由以下几种创建对象的方式:
(1)使用new关键字直接创建对象
(2)通过反射机制创建对象
(3)通过clone()方法创建对象
(4)通过工厂类创建对象
接下来我们学习使用工厂类创建对象
工厂模式介绍
工厂模式的定义
“Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.”(在基类中定义创建对象的一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟到子类中进行。)
工厂模式的分类
- 简单工厂模式:允许接口创建对象,但不会暴露对象的创建逻辑。
- 工厂方法模式:允许接口创建对象,但使用哪个类来创建对象,则时交由子类决定的。
- 抽象工厂模式:抽象工厂时一个能够创建一系列相关的对象而无需指定/公开其具体类的接口。
在开源框架中的使用
- Spring中同通过getBean("xxx")获取Bean;
- Java消息服务JMS中
使用工厂模式的优点
- 解耦:把对象的创建和使用分开
- 降低代码重复:如果创建某个对象的过程很复杂,需要一定的代码量,而且很多地方都要用到,那么就会由很多的重复代码
- 降低维护成本:由于创建过程都由工厂统一管理,所有发生业务逻辑变化,不需要找到所有需要创建某个对象的地方去逐个修正,只需要在工厂里修改即可,降低维护成本。
简单工厂模式
工厂可以帮助开发人员创建不同类型的对象,而不是直接对对象实例化。
介绍
严格来讲,简单工厂模式并不算23种常见的设计模式之一,它只算工厂模式的一个特殊实现。简单工厂模式在实际中用的比其他两种要少得多。
它违背了“开闭原则”(可以通过反射来避免),因为每次添加一个功能,都需要在switch-case或者if-else语句中去修改代码,添加分支条件。
适用场景
- 需要创建的对象较少。
- 客户端不关心对象的创建过程。
简单工厂模式角色分配
- 工厂角色:负责实现创建所有实例的内部逻辑,工厂类可以被外界直接调用,创建所需的产品对象。
- 抽象产品角色:所需创建对象的父类
- 具体产品角色:某个具体类的实例
简单工厂实例
//创建Shape接口
public interface Shape {
void draw();
}
//圆形
public class Circle implements Shape {
public Circle() {
System.out.println("Circle");
}
@Override
public void draw() {
System.out.println("Draw Circle");
}
}
//长方形
public class Rectangle implements Shape {
public Rectangle() {
System.out.println("Rectangle");
}
@Override
public void draw() {
System.out.println("Draw Rectangle");
}
}
//正方形
public class Square implements Shape {
public Square() {
System.out.println("Square");
}
@Override
public void draw() {
System.out.println("Draw Square");
}
}
//创建工厂类
public class ShapeFactory {
// 使用 getShape 方法获取形状类型的对象
public static Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
} else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
return new Rectangle();
} else if (shapeType.equalsIgnoreCase("SQUARE")) {
return new Square();
}
return null;
}
}
//测试方法
public class Test {
public static void main(String[] args) {
// 获取 Circle 的对象,并调用它的 draw 方法
Shape circle = ShapeFactory.getShape("CIRCLE");
circle.draw();
// 获取 Rectangle 的对象,并调用它的 draw 方法
Shape rectangle = ShapeFactory.getShape("RECTANGLE");
rectangle.draw();
// 获取 Square 的对象,并调用它的 draw 方法
Shape square = ShapeFactory.getShape("SQUARE");
square.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;
}
}
测试方法:
Circle circle = (Circle) ShapeFactory2.getClass(com.example.leanspringboot.designpattern.business.impl.Circle.class);
circle.draw();
这种方式虽然符合了开闭原则,但是每一次传入的都是全部路径,比较麻烦。改善方式可以通过 反射+配置文件的形式来改善,这种方式使用的也是比较多的。
工厂方法模式
介绍
这是工厂模式使用最多的一种,工厂方法模式是简单工厂的进一步深化,在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同对象提供不同的工厂。也就是说每个对象都有一个与之对应的工厂。
适用创景
- 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要指定具体产品类的类名,只需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
- 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无需关心时哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或者数据库中。
工厂方法模式角色分配
- 抽象工厂角色:是工厂方法模式的核心,与应用程序无关,任何在模式中创建的对象的工厂类必须实现这个接口。
- 具体工厂角色:这是实现抽象工厂接口的具体工厂类,包含于应用程序密切相关的逻辑,并且受到应用程序调用以创建某一种产品对象。
- 抽象产品角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
- 具体产品角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的集体工厂创建,它们一一对应。
工厂方法模式实例
1. 增加一个工厂接口
public interface Factory {
Shape getShape();
}
2.增加一组工厂类
public class CircleFactory implements Factory {
@Override
public Shape getShape() {
return new Circle();
}
}
public class RectangleFactory implements Factory {
@Override
public Shape getShape() {
return new Rectangle();
}
}
public class SquareFactory implements Factory {
@Override
public Shape getShape() {
return new Square();
}
}
测试
Factory circleFactory = new CircleFactory();
Shape circle = circleFactory.getShape();
circle.draw();
抽象工厂模式
介绍
在工厂方法模式中,其实我们有一个潜意识,那就是我们生成的都是同一类产品。抽象工厂就是抽象工厂方法的进一步深化,在这个模式中的工厂类不单单可以创建一种产品,而是可以创建一组产品。
适用场景
- 和工厂方法一样客户的不需要知道它所创建的对象的类
- 需要一组对象共同完成某种功能时,并且可能存在多组对象完成不同功能的情况。(同属于同一个产品族的产品)
- 系统结构稳定,不会频繁的增加对象。(因为一旦增加就需要修改原有代码,不符合开闭原则)
抽象工厂方法模式角色分配
- 抽象工厂(AbstractFactory)角色 :是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
- 具体工厂类(ConreteFactory)角色 :这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建某一种产品对象。
- 抽象产品(Abstract Product)角色 :工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
- 具体产品(Concrete Product)角色 :抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。在抽象工厂中创建的产品属于同一产品族,这不同于工厂模式中的工厂只创建单一产品,我后面也会详解介绍到。
抽象工厂的工厂和工厂方法总的工厂有什么区别
抽象工厂是生产一整套有产品的(至少要生产两个产品),这些产品必须相互是有关系或有依赖的,而工厂方法中的工厂是生产单一产品的工厂。
抽象工厂模式实例
不知道大家玩过穿越火线或者吃鸡这类游戏了吗,游戏中存在各种枪。我们假设现在存在AK、M4A1两类枪,每一种枪对应一种子弹。我们现在这样考虑生产AK的工厂可以顺便生产AK使用的子弹,生产M4A1的工厂可以顺便生产M4A1使用的子弹。(AK工厂生产AK系列产品包括子弹啊,AK枪的类型啊这些,M4A1工厂同理)
1. 创建相关接口
枪
public interface Gun {
void shooting();
}
子弹
public interface Bullet {
void load();
}
2. 创建接口对应实现类
AK类
public class AK implements Gun{
@Override
public void shooting() {
System.out.println("shooting with AK");
}
}
M4A1类
public class M4A1 implements Gun {
@Override
public void shooting() {
System.out.println("shooting with M4A1");
}
}
AK子弹类
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
M4A1子弹类
public class M4A1
_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with M4A1");
}
}
3. 创建工厂接口
public interface Factory {
public Gun produceGun();
public Bullet produceBullet();
}
4. 创建具体工厂
生产AK和AK子弹的工厂
public class AK_Factory implements Factory{
@Override
public Gun produceGun() {
return new AK();
}
@Override
public Bullet produceBullet() {
return new AK_Bullet();
}
}
生产M4A1和M4A1子弹的工厂
public class M4A1_Factory implements Factory{
@Override
public Gun produceGun() {
return new M4A1();
}
@Override
public Bullet produceBullet() {
return new M4A1_Bullet();
}
}
测试
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();
}
}
网友评论