定义一个工厂类,并提供一个抽象的工厂方法,该方法通过传入不同的参数而创建不同的产品返回,且所有产品类有同一个父类。
角色与理解- 简单工厂模式中的类存在以下几种角色:
- Product(抽象产品角色):所有具体产品的父类
- Factory(工厂角色):实现产品创建逻辑的类
- ConcreteProduct(具体产品角色) : 继承自抽象产品类的具体实现类
- 工厂类中包含静态工厂方法,出参为产品类,客户端通过传入不同入参去调用静态
- 工厂方法去获取不同的具体产品类
- 工厂类中的静态工厂方法通过if else 判断去实例化不同的具体产品类
定义个用于创建对象的接口,让子类决定将哪一个产品实例化。工厂方法模式让一个类的实例化延迟到工厂的子类。工厂方法模式简称为工厂模式,又可称作虚拟构造器模式,或多态工厂模式。
角色与理解- 工厂模式中的类共分为以下几种角色:
- Factory(抽象工厂):提供具体工厂所需要实现的接口集合,供客户端调用
- ConcreteFactory(具体工厂):每一个具体的工厂生产一种具体的产品
- Product(抽象产品):所有具体产品的父类
- ConcreteProduct(具体产品):实现抽象产品类的具体的类,与具体工厂一一对应
- 实例化具体工厂并将指针赋予抽象工厂
- 调用抽象工厂的工厂方法,创建具体产品
提供一个创建一系列相关或者相互依赖的类的工厂接口,他包含多个各类的工厂方法,即一个工厂类能创建多个产品。
角色与理解- 抽象工厂模式总共包含如下四种角色:
- AbstractFactory(抽象工厂):包含多个创建同一产品族中产品的抽象工厂方法的抽象类,一个抽象工厂定义了一个输出的产品族
- ConcreteFactory(具体工厂):抽象工厂的实现
- AbstractProduct(抽象产品):所有具体产品的父类,这里指单一产品的父类而不是一个产品族的共同父类
- ConcreteProduct(具体产品):具体的产品
- 实际上抽象工厂模式与工厂方法模式抽象产品与具体产品的角色是一致的,不同的只是工厂定义的不同,工厂方法中的工厂只生产单一产品,而抽象工厂的工厂生产的是一个产品族的产品
有如下三个需求:
1 任意定制交通工具
2 任意定制交通工具生产过程
3 任意定制产品一族,并可扩展
实现定义交通工具代码
public class Car {
public void go() {
System.out.println(" car go sousousou ...");
}
}
public class Plane {
public void go() {
System.out.println("✈️ plan flying wuwuwu ...");
}
}
public class Broom {
public void go() {
System.out.println("粒 broom flying sousousou ...");
}
}
主类,相当于司机
先开汽车
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.go();
}
}
输出如下
car go sousousou ...
但是我们这时想把交通工具换成飞机,代码改动如下
public class Main {
public static void main(String[] args) {
// Car car = new Car();
// car.go();
Plane plane = new Plane();
plane.go();
}
}
这样来看,我们换交通工具,要改动几乎所有代码,很不方便
于是,我们想,交通工具都是一类东西,是否可以让它们继承同一父类或实现同一接口
下面我们来看方式二
我们定义接口,可移动的,并且有个go方法
public interface Moveable {
void go();
}
具体的实现类改造如下(飞机和扫帚的代码类似,此处省略)
public class Car implements Moveable {
@Override
public void go() {
System.out.println(" car go sousousou ...");
}
}
主类如下
这样,改动时,仅需要改动new后面的实现,相比方式1改动的少一些
public class Main {
public static void main(String[] args) {
// 这样改动交通工具时,仅需要改后面的new .. 即可
Moveable moveable = new Car();
moveable.go();
}
}
下面我们将用设计模式来重构代码
需求 2 2.1 简单工厂定义一个类,生产指定的交通工具
工厂模式一般用在创建对象需要权限控制,或者封装复杂的创建过程而对外仅暴露创建的方法
public class SimpleVehicleFactory {
public static Moveable createVehicle(String type) {
if ("car".equals(type)) {
return new Car();
} else if ("plane".equals(type)) {
return new Plane();
}
return null;
}
}
这样,主类如下
public class Main {
public static void main(String[] args) {
Moveable moveable = SimpleVehicleFactory.createVehicle("plane");
assert moveable != null;
moveable.go();
}
}
2.2 工厂方法
为每个交通工具定义一个工厂
现在我们实现了任意定制交通工具:实现Moveable接口即可;任意定义生产过程:新写一个工厂。
但这个方式的问题是,每新增一个交通工具,我们都需要定义一个工厂,然后主类代码也需要修改
public class CarFactory {
public Car createCar() {
//加入日志
System.out.println("a car created.");
return new Car();
}
}
需求 3
3.1 原始方式
有如下场景:一个司机开着车,拿着武器,吃着东西。
开着车
public class Car {
public void go() {
System.out.println(" car go sousousou ...");
}
}
武器是ak47
public class AK47 {
public void shoot() {
System.out.println("ak47 tututu ...");
}
}
吃的是面包
public class Bread {
public void printName() {
System.out.println("我是面包味多美 ...");
}
}
主类如下
public class Main {
public static void main(String[] args) {
Car c = new Car();
c.go();
AK47 ak47 = new AK47();
ak47.shoot();
Bread bread = new Bread();
bread.printName();
}
}
输出如下
这是个现代人,开着骑车,吃着面包,拿着ak
如果是个魔法人,可能就是骑着扫帚,吃着蘑菇,拿着魔法棒
这样我们怎么定义呢
定义一个抽象类,交通工具
public abstract class Vehicle {
public abstract void go();
}
抽象类,食物
public abstract class Food {
public abstract void printName();
}
抽象类,武器
public abstract class Weapon {
public abstract void shoot();
}
现代版实现三个抽象类
public class Car extends Vehicle {
@Override
public void go() {
System.out.println(" car go sousousou ...");
}
}
public class Bread extends Food {
@Override
public void printName() {
System.out.println("我是面包味多美 ...");
}
}
public class AK47 extends Weapon {
@Override
public void shoot() {
System.out.println("ak47 tututu ...");
}
}
定义抽象工厂,抽象类,生产三种抽象产品
public abstract class AbstractFactory {
public abstract Vehicle createVehicle();
public abstract Food createFood();
public abstract Weapon createWeapon();
}
定义一个现代版工厂,生产三种现代产品
public class ModernFactory extends AbstractFactory {
@Override
public Vehicle createVehicle() {
return new Car();
}
@Override
public Food createFood() {
return new Bread();
}
@Override
public Weapon createWeapon() {
return new AK47();
}
}
这时,我们的主类如下
public class Main {
public static void main(String[] args) {
AbstractFactory factory = new ModernFactory();
Vehicle vehicle = factory.createVehicle();
vehicle.go();
Weapon weapon = factory.createWeapon();
weapon.shoot();
Food food = factory.createFood();
food.printName();
}
}
现代版输出如下
当我们需要魔法世界的实现时,仅需要定义魔法的工厂,和三个产品,然后仅改动主类中new工厂一行代码即可。
public class MagicFactory extends AbstractFactory {
@Override
public Vehicle createVehicle() {
return new Broom();
}
@Override
public Food createFood() {
return new Mushroom();
}
@Override
public Weapon createWeapon() {
return new MagicWand();
}
}
public class Broom extends Vehicle {
@Override
public void go() {
System.out.println("粒 broom flying sousousou ...");
}
}
public class Mushroom extends Food {
@Override
public void printName() {
System.out.println("我是毒蘑菇");
}
}
public class MagicWand extends Weapon {
@Override
public void shoot() {
System.out.println("魔法棒电dian dian ...");
}
}
主类如下
public class Main {
public static void main(String[] args) {
AbstractFactory factory = new MagicFactory();
Vehicle vehicle = factory.createVehicle();
vehicle.go();
Weapon weapon = factory.createWeapon();
weapon.shoot();
Food food = factory.createFood();
food.printName();
}
}
输出如下
这样我们可以做到任意定制产品一族,并且改动对源代码影响很小。
如果把工厂配置到配置文件里,改动的影响将会更小。
工厂设计模式的类图如下:



