设计模式(四)—工厂模式之工厂方法

一、定义

        Define an interface for creating an object,but let subclasses decide which class to
instantiate.Factory Method lets a class defer instantiation to subclasses.即定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类来完成
       主要的目的是定义一个创建对象的接⼝,让其⼦类⾃己决定实例化哪一个具体的工厂类,⼯⼚模式使其创建具体实例的过程延迟到子类进行。
       简单总结就是为了提供代码结构的可扩展性,屏蔽每⼀个功能类中的具体实现逻辑。让外部可以更简单的调用即可

二、类图

三、四个重要角色

1.Factory:工厂接口角色

        工厂接口角色是所创建的具体产品工厂类的父类或接口,负责描述所有实例对象的共同接口或抽象类。规定了工厂对象的共同方法,是公具体工厂的公共接口。

2.具体工厂类角色

        工厂接口角色的子类,用来被外界调用,描述具体的工厂;实现FactoryMethod工厂方法创建具体产品的实例

3.Product:抽象产品角色

        抽象产品角色是所创建的具体产品类的父类或接口,负责描述所有实例对象的共同接口或抽象类。规定了产品对象的共同方法。

4.ConcreteProduct:具体产品角色

        实现了抽象产品类或接口,定义了具体产品的特定行为和属性,所有创建的对象都充当这个角色的某个具体类的实例。

四、实际案例

1.定义抽象产品角色接口

public interface LightingProduct {
    //定义一个生产节能灯产品的方法
    public void energySavingLightProduct();
}

2.定义两个具体品牌的节能灯产品

public class PanasonicLighting implements LightingProduct{
    @Override
    public void energySavingLightProduct() {
        System.out.println("松下-节能灯");
    }
}
 
 
public class PhilipsLighting implements LightingProduct{
    @Override
    public void energySavingLightProduct() {
        System.out.println("飞利浦-节能灯");
    }
}

3.定义工厂方法接口

public interface FactoryMethod {
    public  LightingProduct makeLightingProduct();
}

4.定义两个具体工厂生产具体节能灯产品

//生产松下节能灯的工厂
public class PanasonicLightingFactory implements FactoryMethod{
    @Override
    public LightingProduct makeLightingProduct() {
        return new PanasonicLighting();
    }
}

//生产飞利浦节能灯的工厂
public class PhilipsLightingFactory implements FactoryMethod{
    @Override
    public LightingProduct makeLightingProduct() {
        return new PhilipsLighting();
    }
}

 5.模拟产品的订购

public class FactoryMethodMain {
    public static void main(String[] args) {
        //订购松下节能灯
        FactoryMethod factoryMethod = new PanasonicLightingFactory();
        factoryMethod.makeLightingProduct().energySavingLightProduct();
        //订购飞利浦节能灯
        factoryMethod = new PhilipsLightingFactory();
        factoryMethod.makeLightingProduct().energySavingLightProduct(); 
    }
}

6.订购结果

松下-节能灯
飞利浦-节能灯

7.通用工厂类改造

       上述第4步中,如果需要创建多中类型的节能灯时,那边需要创建大量的对应的工厂类,那么是否可以进行对具体工厂类进行改造呢?答案是可以的,使用泛型+反射的方式来实现

①.通过工厂接口定义

public interface GeneralFactoryMethod {
    //泛型对象继承LightingProduct
    public  <T extends LightingProduct> T makeLightingProduct(Class<T> clazz);
}

②.通用工厂方法实现

public class GeneralLightingFactory implements GeneralFactoryMethod{
    @Override
    public <T extends LightingProduct> T makeLightingProduct(Class<T> clazz) {
        LightingProduct lightingProduct =null;
        try {
//通过反射来创建需求定制的产品
            lightingProduct = (LightingProduct)Class.forName(clazz.getName()).newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return (T)lightingProduct;
    }
}

③.订购商品

public class FactoryMethodMain {
    public static void main(String[] args) {
        //创建通用工厂对象   
        GeneralFactoryMethod generalFactoryMethod = new GeneralLightingFactory();
        //订购松下节能灯
        generalFactoryMethod.makeLightingProduct(PanasonicLighting.class).energySavingLightProduct();
        //订购飞利浦节能灯
        generalFactoryMethod.makeLightingProduct(PhilipsLighting.class).energySavingLightProduct();
    }
}

④.订购结果

松下-节能灯
飞利浦-节能灯

五、适用场景

      ①.一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类
      ②.一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展
      ③.将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

六、工厂方法模式的优缺点

1.优点

     ①.在工厂方法模式中,工厂方法用来创建客户具体所需要的产品,用户只需要关心所需产品对应的工厂,无须关心其具体的创建细节,甚至无须知道具体产品类的类名。
     ②.基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。因此工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
     ③.使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了

2.缺点

    ①.在添加新的产品时,需要重新编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
    ②.由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

参考资料:工厂方法模式(Factory Method Pattern) — Graphic Design Patterns

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值