概述
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
简单工厂模式
概述:
定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类。
优点:
工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点:
由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,同样破坏了“开闭原则”;在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
代码演示如下:
public interface Shape {
void draw();
}
创建一个shape接口,创建不同的类实现shape接口从而实现不同逻辑的draw()方法。
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
创建一个工厂,生成基于给定信息的实体类的对象。
public class ShapeFactory {
//使用 getShape 方法获取形状类型的对象
public 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 FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
//获取 Circle 的对象,并调用它的 draw 方法
Shape shape1 = shapeFactory.getShape("CIRCLE");
//调用 Circle 的 draw 方法
shape1.draw();
//获取 Rectangle 的对象,并调用它的 draw 方法
Shape shape2 = shapeFactory.getShape("RECTANGLE");
//调用 Rectangle 的 draw 方法
shape2.draw();
//获取 Square 的对象,并调用它的 draw 方法
Shape shape3 = shapeFactory.getShape("SQUARE");
//调用 Square 的 draw 方法
shape3.draw();
}
}
输出如下结果:
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
总结:简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象。
工厂方法模式
如上方式带来的问题就是太多的if,else的判断了,如果是针对业务逻辑来说的话,假如说要新增某个工厂则就又需要重新写之前的业务逻辑了,那么如何解决呢,就需要采用工厂方法模式,这里采用交通工具为例。
public interface Moveable {
void go();
}
创建一个接口,里面的go方法是为了实现不同的交通工具运行的方式。
public class Car implements Moveable {
public void go() {
System.out.println("Car go wuwuwuwuw....");
}
}
public class Plane implements Moveable {
public void go() {
System.out.println("plane flying shushua....");
}
}
在实现对应的工厂类
public class CarFactory {
public Moveable create() {
System.out.println("a car created!");
return new Car();
}
}
public class PlaneFactory {
public Moveable create() {
System.out.println("a plane created!");
return new Plane();
}
}
再写对应的main方法
public class Main {
public static void main(String[] args) {
Moveable m = new CarFactory().create();
m.go();
Moveable m1 = new PlaneFactory().create();
m1.go();
}
}
如上方式就是为每一个交通工具子类建立一个对应的工厂子类,这些工厂子类实现同一个抽象工厂接口。这样,创建不同品牌的交通工具,只需要实现不同的工厂子类。当有新交通工具加入时,新建具体工厂继承抽象工厂,而不用修改任何一个类。
但是也会有相应的缺点:
假如某个具体产品类需要进行一定的修改,很可能需要修改对应的工厂类。当同时需要修改多个产品类的时候,对工厂类的修改会变得相当麻烦。
总结
工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量的if-else判断。
抽象工厂模式
工厂方法模式每个具体工厂类只完成单个实例的创建,所以它具有很好的可扩展性。但是在现实生活中,一个工厂只创建单个产品这样的例子很少,因为现在的工厂都多元化了,一个工厂创建一系列的产品,如果我们要设计这样的系统时,工厂方法模式显然在这里不适用,然后抽象工厂模式却可以很好地解决一系列产品创建的问题。
在抽象工厂模式的结构图有以下角色:
抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同的产品。
抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
具体产品(ConcreteProduct):实现抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
如下我们以现代工厂和魔法工厂举例:
1.首先定义抽象工厂(包含公有的实现方式不同的工厂产品,这里是创建食物,武器,和交通工具)
public abstract class AbastractFactory {
abstract Food createFood();
abstract Vehicle createVehicle();
abstract Weapon createWeapon();
}
2.定义抽象产品
public abstract class Food {
abstract void printName();
}
public abstract class Vehicle { //interface
abstract void go();
}
public abstract class Weapon {
abstract void shoot();
}
3.定义具体产品
public class AK47 extends Weapon{
public void shoot() {
System.out.println("tututututu....");
}
}
public class Bread extends Food{
public void printName() {
System.out.println("wdm");
}
}
public class Car extends Vehicle{
public void go() {
System.out.println("Car go wuwuwuwuw....");
}
}
public class MagicStick extends Weapon{
public void shoot() {
System.out.println("diandian....");
}
}
public class MushRoom extends Food{
public void printName() {
System.out.println("dmg");
}
}
public class Broom extends Vehicle{
public void go() {
System.out.println("Broom go titititi...");
}
}
4.定义具体工厂(分为现代工厂以及魔法工厂)
public class ModernFactory extends AbastractFactory {
@Override
Food createFood() {
return new Bread();
}
@Override
Vehicle createVehicle() {
return new Car();
}
@Override
Weapon createWeapon() {
return new AK47();
}
}
public class MagicFactory extends AbastractFactory {
@Override
Food createFood() {
return new MushRoom();
}
@Override
Vehicle createVehicle() {
return new Broom();
}
@Override
Weapon createWeapon() {
return new MagicStick();
}
}
下面看Main方法
public class Main {
public static void main(String[] args) {
AbastractFactory f = new ModernFactory();
Vehicle c = f.createVehicle();
c.go();
Weapon w = f.createWeapon();
w.shoot();
Food b = f.createFood();
b.printName();
AbastractFactory f1 = new MagicFactory();
Vehicle c1 = f1.createVehicle();
c1.go();
Weapon w1 = f1.createWeapon();
w1.shoot();
Food b1 = f1.createFood();
b1.printName();
}
}
运行结果如下:
抽象工厂模式的优缺点
1、优点
(1)具体产品在应用层代码隔离,无须关心创建细节
(2)将一系列的产品族统一到一起创建
2、缺点
(1)规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口
(2)增加了系统的抽象性和理解难度
总结
抽象工厂:多个工厂类,多个产品抽象类,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。
最后:
总的来说工厂方法模式可以很方便的扩展产品比如说上面写的交通工具类可以很方便的扩展出游艇,飞船之类的,但是生产新的产品则就比较复杂了,抽象工厂模式从产品维度方向扩展比较困难,比如说从食物,武器和交通工具这个基础上再扩展玩的,旅游的这些,则需要改的业务代码变得繁杂。