设计模式之 --- 工厂模式(上)

设计模式之 --- 工厂模式(上)

简介

工厂设计模式专门负责将大量有共同接口的类实例化,工厂模式可以动态的决定将哪一个类实例化,不必事先知道每次要实例化那一个类,工厂模式有以下几种形态:

一、简单工厂模式

简介

​ 简单工厂模式(Simple Factory Pattern ):又称为静态工厂方法模式(Static Factory Method ),是类创建型设计模式之一。

​ 我们可以通过对工厂方法传入不同参数来返回具体类的实例对象,并且所有返回的实例对象都具有共同的父类。

使用场景

​ 将类的实例化操作和对象的使用分开,让用户可以不用知道具体实例化的细节直接使用,从而避免在客户端代中码显示指定,实现解耦。

​ 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。

​ 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。

UML类图

示例

抽象产品类 《汽车》

/**
 * 抽象产品类 
 */
public interface Car {
    /**
     * 作为汽车都可以跑
     */
    void run();

    /**
     * 作为汽车也可以刹车
     */
    void braking();
}

具体产品类 《小轿车》

/**
 *  小轿车
 */
public class SedanCar implements Car {
    public void run() {
        System.out.println("小轿车启动了!");
    }

    public void braking() {
        System.out.println("小轿车刹车了!");
    }
}

具体产品类 《SUV汽车》

/**
 * SUV 型汽车
 */
public class SuvCar implements Car {
    public void run() {
        System.out.println("SUV 启动了!");
    }
  
    public void braking() {
        System.out.println("SUV 刹车了!");
    }
}

具体工厂类

/**
 *  具体工厂类
 */
public final class CarFactory {
    /**
     * 小轿车
     */
    public static final String TYPE_SEDAN = "SEDAN_CAR";

    /**
     * SUV
     */
    public static final String TYPE_SUV = "SUV";

    /**
     * 静态工厂方法
     *
     * @param type 汽车类型
     * @return
     */
    public static Car create(String type) {
        if (type.equals(TYPE_SEDAN)) {
            return new SedanCar();
        } else if (type.equals(TYPE_SUV)) {
            return new SuvCar();
        }else {
            throw new RuntimeException("没有找到匹配的对象!");
        }
    }
}

测试

/**
 * 工厂模式测试类
 */
public class FactoryTest {
    public static void main(String[] args) {
        // 简单工厂模式测试
        Car sedanCar = CarFactory.create(CarFactory.TYPE_SEDAN);
        Car suvCar = CarFactory.create(CarFactory.TYPE_SUV);
        sedanCar.run();
        sedanCar.braking();
        suvCar.run();
        suvCar.braking();
    }
}

角色简介

从上面的类图及示例可以看出,简单工厂涉及到工厂角色、抽象产品角色、具体产品角色等三个角色。

  • Factory : 工厂角色

    工厂角色负责创建所有实例的内部逻辑实现,由一个具体的Java类实现

  • Car:抽象的产品角色

    抽象产品角色是创建所有具体实例对象的共同父类,负责描述所有实例所共用的公共接口,可以由一个Java接口或者Java抽象类实现

  • SedanCar、SuvCar:具体产品角色

    具体产品角色是创建目标,为实现抽象产品角色的某个具体产品对象,由一个具体Java类实现

优点

​ 该模式的核心是工厂类,这个类含有必要的逻辑判断,可以决定在什么时候创建哪一个产品类的实例。而客户端可以免除直接创建产品对象的责任,仅仅负责“消费”产品。简单工厂模式通过这种方法实现了对责任的分割。

缺点

​ 当产品有复杂的多层次等级结构时,工厂类只有他自己,以不变应万变就是模式的缺点

​ 这个工厂类集中了所有产品的创建逻辑,形成了一个无所不知的全能类,有人把这种类叫做上帝类(God Class),他将负责所有产品创建,一旦这个工厂不能正常工作,那整个产品生产线都将受到影响

​ 将这么多的逻辑放到一个类里面的另外一个缺点是,当产品类有不同的接口种类时,工厂类需要判断在什么时候创建某种产品,这种对时机的判断和对哪一种具体产品的判断逻辑混合在一起,使得系统将来的功能扩展变的困难,这一缺点将在工厂方法模式中克服

​ 由于简单工厂模式使用了静态方法作为工厂方法,而静态方法无法由子类继承,因此工厂角色无法形成基于继承的等级结构,这一缺点将在工厂方法模式中克服

​ 简单工厂模式只在有限程度上支持了“开-闭”原则

二、工厂方法模式

简介

​ 工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(VirtualConstructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式。

​ 工厂方法模式是简单工厂模式的进一步抽象和推广,由于使用了多态性,工厂方法保持了简单工厂模式的优点,而且克服了它的缺点

使用场景

​ 在任何需要生成复杂对象的地方,都可以使用工厂方法模式,复杂对象适合使用工厂模式,用new就可以完成创建的对象无需使用工厂模式

​ 一个类通过其子类来指定创建哪个对象,在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,这种方式可以使系统更容易扩展

UML类图

示例

还是上面的示例进行改造如下:

抽象产品类 《Car》

/**
 * 抽象产品类
 */
public interface Car {
    /**
     * 作为汽车都可以跑
     */
    void run();

    /**
     * 作为汽车也可以刹车
     */
    void braking();
}

具体产品类 《SedanCar》

/**
 *  小轿车
 */
public class SedanCar implements Car {
    public void run() {
        System.out.println("小轿车启动了!");
    }

    public void braking() {
        System.out.println("小轿车刹车了!");
    }
}

具体产品类 《SuvCar》

/**
 * SUV 型汽车
 */
public class SuvCar implements Car {
    public void run() {
        System.out.println("SUV 启动了!");
    }

    public void braking() {
        System.out.println("SUV 刹车了!");
    }
}

抽象工厂类 《CarFactory》

public interface CarFactory {
    /**
     *  抽象工厂方法,具体生产什么对象由具体子类提供
     * @return 返回具体实例对象
     */
    Car create();
}

具体工厂类 《SedanCarFactory》

public class SedanCarFactory implements CarFactory {
    public Car create() {
        return new SedanCar();
    }
}

具体工厂类 《SuvCarFactory》

public class SuvCarFactory implements CarFactory {
    public Car create() {
        return new SuvCar();
    }
}

测试

/**
 * 工厂模式测试类
 */
public class FactoryTest {
    public static void main(String[] args) {
        // 工厂方法模式测试
        SedanCarFactory sedanCarFactory = new SedanCarFactory();
        Car car = sedanCarFactory.create();
        car.run();
        car.braking();

        SuvCarFactory suvCarFactory = new SuvCarFactory();
        Car carSuv = suvCarFactory.create();
        carSuv.run();
        carSuv.braking();
    }
}

角色简介

  • 抽象产品角色:Car

    工厂方法模式所创建对象的超类型,也就是具体产品对象的共同父类或者共同拥有的接口

  • 具体产品角色:SedanCar、SuvCar

    这个角色实现了抽象产品角色所声明的接口,工厂方法所创建的每一个对象都是某个具体产品角色的实例

  • 抽象工厂角色:CarFactory

    担任这个角色的是工厂方法模式的核心,它是与应用程序无关的,任何在模式中创建对象的工厂类必须实现这个接口

  • 具体工厂角色:SedanCarFactory、SuvCarFactory

    这个角色实现了抽象工厂的接口具体的Java类,这个角色含有与应用密切相关的逻辑,并且受到应用程序的调用创建产品对象

工厂方法模式改造

​ 以上实现方式比较常见,有时候我们也可以利用反射的方式简洁地来生产具体产品对象,此时,只需要我们在工厂方法中传入一个Class类来决定是哪一个产品类:

/**
 * 工厂方法的另一种写法
 *
 * 使用反射可以更简洁的生产产品对象
 */
public interface CarFactory2 {
    <T extends Car> T create(Class<T> clazz);
}

对于具体的工厂类,则通过反射获取类的实例即可:

public class CarFactory2Impl implements CarFactory2 {
    public <T extends Car> T create(Class<T> clazz) {
        Car car = null;
        try {
            car = (Car) Class.forName(clazz.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return (T) car;
    }
}

最后我们看下测试实现:

public class FactoryTest {
    public static void main(String[] args) {
        // 工厂方法模式测试第二种写法
        CarFactory2Impl carFactory2 = new CarFactory2Impl();
        Car sedanCar1 = carFactory2.create(SedanCar.class);
        sedanCar1.run();
        sedanCar1.braking();

        Car suvCar1 = carFactory2.create(SuvCar.class);
        suvCar1.run();
        suvCar1.braking();
    }
}

打印结果:

小轿车启动了!
小轿车刹车了!
SUV 启动了!
SUV 刹车了!

优点

​ 首先要说的是工厂方法模式克服简单工厂模式的缺点

​ 工厂方法模式通过抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触具体产品生产的实现细节,这种进一步抽象化的结果使工厂方法模式可以允许在不修改具体工厂角色的情况下引进新的产品,符合了“开-闭”原则,这一点比简单工厂模式更优秀

​ 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类 ,这样的设计可以提高系统扩展性

缺点

​ 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度和导致类结构的复杂化,有更多的类需要编译和运行,也会给系统带来一些额外的开销。

总结

​ 总的来说,工厂设计模式是一个很好的设计模式,它的优点和缺点已经总结了,在平常的开发中这种缺点也是不可避免的,所在在某些简单或者复杂的场景下,对于工厂方法模式的使用,需要设计者自己来权衡 其中的利弊了

参考资料

Java与模式 - 书

Android 源码设计模式解析与实战 - 书

猜你喜欢

转载自www.cnblogs.com/mr-wang1/p/10638205.html
今日推荐