设计模式--工厂模式分析总结

先来一个生动的例子:

  大众汽车的MQB平台是现在非常出名的横置发动机模块化生产平台,从这个平台上出生了许多的广为人知的汽车型号,如奥迪TT、大众Polo、高尔夫等等。抽象化思考,这些汽车都出自一个生产平台,而不是每辆车都单独占有一个平台,那么问题来了,如何让一个平台生产出多个型号的汽车呢?

  我们以上述三种车型为例,先定义出三种车的类

public class AudiTT {
    public void run() {
        System.out.println("AudiTT run...");
    }
}

public class Polo {
    public void run() {
        System.out.println("Polo run...");
    }
}

public class Golf {
    public void run() {
        System.out.println("Golf run...");
    }
}

  如何让平台生产三种型号的车型呢?有同学就会提出这样的做法,让平台实现每个型号的生产方法不就行了,于是乎有了下面的代码

public class Factory {
    public AudiTT produceAudiTT() {
        return new AudiTT();
    }
    public Polo producePolo() {
        return new Polo();
    }
    public Golf produceGolf() {
        return new Golf();
    }
}

  写个场景类测试一下

public class Test {
    public static void main(String[] args) {
        Factory factory = new Factory();
        AudiTT audiTT = factory.produceAudiTT();
        Polo polo = factory.producePolo();
        audiTT.run();
        polo.run();
    }
}

  输出结果

AudiTT run...
Polo run...

  这么做看起来似乎是可行的,但是我们注意到,这个工厂类实际上没有一点作用,相当于我们自己new了一个具体的汽车对象,在接收工厂生产出的对象时,也不能用统一的类去接收,且我们每增加一个汽车类,就需要修改工厂类,工厂类和汽车类之间耦合性极强,增加出错风险,代码的复用性也不高,这是不符合设计原则的。

  为了增强类间解耦合,我们引入抽象类,定义产品的公共行为,此例中就是run()方法,我们定义Car类为汽车类的公共父类

public abstract class Car {
    public abstract void run();
}

  此时,三个汽车类相应继承Car类,并重写run()方法

public class AudiTT extends Car{
    @Override
    public void run() {
        System.out.println("AudiTT run...");
    }
}

public class Polo extends Car {
    @Override
    public void run() {
        System.out.println("Polo run...");
    }
}

public class Golf extends Car{
    @Override
    public void run() {
        System.out.println("Golf run...");
    }
}

  此时,工厂类却可以发生重大变化,我们引入抽象工厂类

public abstract class AbsFactory {
    public abstract <T extends Car> T produce(Class<T> clazz);
}

  引入具体工厂类继承抽象工厂,重写生产方法

public class Factory extends AbsFactory{

    @Override
    public <T extends Car> T produce(Class<T> clazz) {
        Car car = null;
        try {
            car = (Car)Class.forName(clazz.getName()).getDeclaredConstructor().newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return (T)car;
    }
}

  写一个场景类进行实验

public class Test {
    public static void main(String[] args) {
        AbsFactory factory = new Factory();
        Car audiTT = factory.produce(AudiTT.class);
        Car polo = factory.produce(Polo.class);
        audiTT.run();
        polo.run();
    }
}

  输出结果:

AudiTT run...
Polo run...

  现在,我们每增加一个汽车类,再也不用修改工厂类,只要传入具体的类对象信息,工厂类都可以按要求生产对应的汽车对象,实现了汽车类和工厂类解耦合,增加了代码复用度。

  我们注意到,在测试类中,我们都是用父类对象去接收子类对象,这在Java中是可行的,利用了Java中子类的向上转型,实现接收变量的统一化,还有就是具体工厂类中,利用了Java的反射功能。

  还可以在抽象产品类中加入所有具体产品类的共有属性和方法,进行扩展,同时,抽象工厂类也可以有多个不同的子类,以实现多个生产不同产品,比如汽车工厂、电脑工厂等等不同性质的产品工厂,进行扩展。

优点:

  使一个类的实例化延迟到子类,实现类间解耦,屏蔽产品类,增强代码复用度。

具体案例

  如果使用JDBC链接数据库,数据库从MySQL变换到Oracle,唯一需要做的就是改变驱动名称,其他都不需要修改  

通用模版

  我们很容易从上述代码中提取出通用模版

  抽象产品类

public abstract class AbsProduct {
    //产品类的公共方法
    public void method1() {
        
    }
    //具体产品类的具体方法,留给子类具体实现
    public abstract void method2();
}

  具体产品类

public class ConcreteProduct extends AbsProduct {
    @Override
    public void method2() {
        
    }
}

  具体产品类可以有多个,越多越能体现工厂模式的优点

  抽象工厂类

public abstract class AbsFactory {
    public abstract <T extends AbsProduct> T produce(Class<T> c);
}

  具体工厂类

public class ConcreteFactory extends AbsFactory {
    @Override
    public <T extends AbsProduct> T produce(Class<T> c) {
        AbsProduct product = null;
        try {
            product = (AbsProduct) Class.forName(c.getName()).getDeclaredConstructor().newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return (T) product;
    }
}

  这只是普通工厂模式的简要介绍,更工厂的抽象工厂模式,留作下一篇总结

 

  

posted @ 2020-06-07 16:13  dwwzone  阅读(268)  评论(0编辑  收藏  举报