1、概述

工厂模式主要是通过把创建对象的代码包装起来,做到创建对象的代码与具体的业务逻辑代码相隔离的目的。

工厂模式可以细分为:简单工厂模式,工厂方法模式,抽象工厂模式。

2、简单工厂模式

简单工厂的标准类图

首先,我们举个例子,我们需要生产3种不同的车类型(电车,油车,混能车),用户自行指定需要什么车,就给用户创建什么车的对象。

分析一下,电车,油车,混能车都是具体的类,他们应该同属于车这个抽象类,然后我们需要建一个工厂类来根据用户的指定,创建指定的车型类。所以再根据上面的图,我们就可以开始写代码模拟实现这个例子。

创建车的抽象接口

public interface Car {
    public void createCar();
}

 创建具体车型类,并实现Car接口

public class Ecar implements Car{
    @Override
    public void createCar() {
        System.out.println("造出电车");
    }
}
public class Ocar implements Car{
    @Override
    public void createCar() {
        System.out.println("造出油车");
    }
}

public class Mcar implements Car{
    @Override
    public void createCar() {
        System.out.println("造出混能车");
    }
}

创建工厂类

public class CarFactory {

    public Car createCar(String s) {
        Car car = null;
        switch (s) {
            case "电车":
                car = new Ecar();
                break;
            case "油车":
                car = new Ocar();
                break;
            case "混能车":
                car = new Mcar();
                break;
        }
        return car;
    }
}

 测试

public class Test1 {
    public static void main(String[] args) {
        CarFactory carFactory = new CarFactory();
        Car car = carFactory.createCar("油车");
        car.createCar();
    }
}
造出油车

 优点:

将对象的创建交给专门的工厂类负责,实现了对象的创建和对象的使用分离。

一个调用者想创建一个对象,只要知道其名称就可以了,灵活性高

屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:

增加新的具体产品需要修改工厂类的判断逻辑代码。违背开闭原则

3、工厂方法模式

那么为了解决简单工厂的违反开闭原则,就出现了工厂方法模式,每一个具体车型类,有一个自己的创建自己对象的工厂,从而避免违法开闭原则。

网上找的工厂方法模式类图参考,结构都相似。

 其他的类不变,我们先修改CarFactory类改为接口。

public interface CarFactory {
    public Car createCar();
}

 创建电车型类的工厂

public class EcarFactory implements CarFactory{
    @Override
    public Car createCar() {
        return new Ecar();
    }
}

 其他的工厂同上,就不写了。

测试

public class Test1 {
    public static void main(String[] args) {
        CarFactory carFactory = new EcarFactory();
        Car car = carFactory.createCar();
        car.createCar();
    }
}
造出电车

优点:

用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。

高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。不会修改原有的代码,不会违法开闭原则。

缺点: 

新产品的创建,只需多写一个相应的工厂类和具体类,灵活度没有简单工厂模式高

类的个数容易过多,增加复杂度。

抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。


4、抽象工厂模式

通过上面工厂方法的缺点可以看到,简单工厂和工厂方法模式都是能生产一种产品,如果我需要创建比亚迪,宝马,奔驰品牌的电车,油车,混能车,上述的工厂模式很难实现,所有我们就可以用到抽象工厂模式。

抽象工厂模式类图

先创建电车,油车,混能车的抽象接口

 这个car写错了写成了cat不过不影响效果

public interface Ecat {
    public void createCat();
}


public interface Mcat {
    public void createCat();
}

public interface Ocat {
    public void createCat();
}

 创建每个牌子车型的具体类

public class BenzEcat implements Ecat {
    @Override
    public void createCat() {
        System.out.println("奔驰电车");
    }
}

public class BmwEcat implements Ecat {
    @Override
    public void createCat() {
        System.out.println("宝马电车");
    }
}

public class BydEcat implements Ecat {
    public void createCat(){
        System.out.println("比亚迪电车");
    }
}

 其他两个车型就不写了,写法类似。

 创建抽象汽车工厂接口

public interface CatFactory {
    public Ecat createEcat();
    public Ocat createOcat();
    public Mcat createMcat();
}

 创建具体品牌的工厂,实现车的接口工厂

public class BydCatFactory implements CatFactory{
    @Override
    public Ecat createEcat() {
        return new BydEcat();
    }

    @Override
    public Ocat createOcat() {
        return new BydOcat();
    }

    @Override
    public Mcat createMcat() {
        return new BydMcat();
    }
}

public class BmwCatFactory implements CatFactory{
    @Override
    public Ecat createEcat() {
        return new BmwEcat();
    }

    @Override
    public Ocat createOcat() {
        return new BmwOcat();
    }

    @Override
    public Mcat createMcat() {
        return new BmwMcat();
    }
}

public class BenzCatFactory implements CatFactory{
    @Override
    public Ecat createEcat() {
        return new BenzEcat();
    }

    @Override
    public Ocat createOcat() {
        return new BenzOcat();
    }

    @Override
    public Mcat createMcat() {
        return new BenzMcat();
    }
}

 测试

public class test1 {
    public static void main(String[] args) {
        //抽象工厂测试
        CatFactory catFactory = new BydCatFactory();
        Ocat ocat = catFactory.createOcat();
        ocat.createCat();
    }
}
比亚迪油车

优点:

增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。

当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。

缺点: 

增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,灵活性低

5、抽象工厂模式改进为简单抽象工厂模式

只用再上述的工厂类,改为下列新的工厂类。

public class SimpleAbstractCatFactory {
    public Ecat createEcat(String brand) {
        Ecat ecat = null;
        switch (brand) {
            case "比亚迪":
                ecat = new BydEcat();
                break;
            case "宝马":
                ecat = new BmwEcat();
                break;
            case "奔驰":
                ecat = new BenzEcat();
                break;
        }
        return ecat;
    }

    public Ocat createOcat(String brand) {
        Ocat ocat = null;
        switch (brand) {
            case "比亚迪":
                ocat = new BydOcat();
                break;
            case "宝马":
                ocat = new BmwOcat();
                break;
            case "奔驰":
                ocat = new BenzOcat();
                break;
        }
        return ocat;
    }

    public Mcat createMcat(String brand) {
        Mcat mcat = null;
        switch (brand) {
            case "比亚迪":
                mcat = new BydMcat();
                break;
            case "宝马":
                mcat = new BmwMcat();
                break;
            case "奔驰":
                mcat = new BenzMcat();
                break;
        }
        return mcat;
    }
}

测试 

        SimpleAbstractCatFactory simpleAbstractCatFactory = new SimpleAbstractCatFactory();
        Ecat ecat = simpleAbstractCatFactory.createEcat("比亚迪");
        ecat.createCat();

 优点:灵活性高。

缺点:违反开闭原则。

6、总结

通过我们上面的各种例子,我们可以发现不管我们怎么修改设计方式,都不能够同时满足灵活性高不违反开闭原则。如果要同时满足的话,就需要引入反射的思想,通过反射+抽象工厂的方式实现。

 

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐