工厂模式详解

工厂模式

简单工厂模式: 简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品 类的实例

简单工厂适 用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如 何创建对象的逻辑不需要关心。

代码案例:

定义一个工厂角色(创建不同的水果)

public class FuritsSimpleFactory {


    private FuritsSimpleFactory(){}


    /**
     * 简单工厂模式根据客户传递的参数来创建实例,客户不需要实例对象是如何产生的
     * @param param 客户传入的参数
     * @return 工厂创建水果的实例
     */
    public static Furits createFurits(String param){
        if(StringUtils.equals(param,"Apple"))
            return new Apple();
        if(StringUtils.equals(param,"Banana"))
            return new Banana();
      throw  new RuntimeException("生产不了此类产品"+param);
    }
}

定义一个抽象产品角色

/**
* @author gege
* @Description
* 抽象产品角色 :是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
* @date 2019/3/14 16:22
*/
public interface Furits {
    void descInfo();
}

 

定义两个具体产品角色

/**
* @author gege
* @Description  具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例
* @date 2019/3/14 16:23
*/
public class Apple implements Furits {
    public void descInfo() {
        System.out.println("I am Apple!");
    }
}


/**
* @author gege
* @Description 具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例
* @date 2019/3/14 16:25
*/
public class Banana implements Furits  {
    public void descInfo() {
        System.out.println("I am Banana!");
    }
}

客户端来获取我们需要的产品

/**
* @author gege
* @Description
* @date 2019/3/14 16:34
*/
public class FuritsSimpleFactoryTest {


    @Test
    public void createFurits() {
        //此处客户端不需要自己动手创建实例  创建的过程交给工厂完成
        Furits furits = FuritsSimpleFactory.createFurits("Apple");
        furits.descInfo();
        furits = FuritsSimpleFactory.createFurits("Banana");
        furits.descInfo();


        //加入客户传入的参数有误  则工厂创建不出我们需要的产品
        furits = FuritsSimpleFactory.createFurits("aaa");
        furits.descInfo();
    }
}

控制台输出

I am Apple!
I am Banana!


java.lang.RuntimeException: 生产不了此类产品aaa


    at org.gege.pattern.factory.simple.FuritsSimpleFactory.createFurits(FuritsSimpleFactory.java:25)
    at org.gege.pattern.factory.simple.FuritsSimpleFactoryTest.createFurits(FuritsSimpleFactoryTest.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

优点:创建产品的过程客户端不需要自己创建  只需传入相应的参数

缺点:客户端传入的参数无法控制,传入有误的参数会导致系统无法正常运行

 

类关系图

客户端调用是简单了,但如果我们业务继续扩展,要增加前端课程,那么工厂中的create()就要根据产品链的丰富每次都要修改代码逻辑。不符合开闭原则。因此,我们对简单工厂还可以继续优化,可以采用反射技术:

 


/**
* @author gege
* @Description 客户端调用是简单了,但如果我们业务继续扩展,要增加前端课程,那么工厂中的
* create()就要根据产品链的丰富每次都要修改代码逻辑。不符合开闭原则。因此,我们
* 对简单工厂还可以继续优化,可以采用反射技术:
* @date 2019/3/14 16:59
*/
public class FuritsSimpleFactoryUpgrade {


    /**
     * 简单工厂模式根据客户传递的参数来创建实例,客户不需要实例对象是如何产生的
     * @param clazz 客户传入的产品的类型
     * @return 工厂创建水果的实例
     */
    public static Furits createFurits2(Class<? extends Furits> clazz){


        try {
            Furits furits = clazz.newInstance();
            return  furits;
        }catch (Exception e){
            throw new RuntimeException("类创建异常");
        }
    }
}    
//此处客户端不需要自己动手创建实例  创建的过程交给工厂完成
  Furits furits = FuritsSimpleFactoryUpgrade.createFurits(Apple.class);
  furits.descInfo();
  furits = FuritsSimpleFactoryUpgrade.createFurits(Banana.class);
  furits.descInfo();


//  furits = FuritsSimpleFactoryUpgrade.createFurits(String.class);
  //改进后此处只能传入 Furits 的子类
  furits = FuritsSimpleFactoryUpgrade.createFurits2(Apple.class);
  furits.descInfo();

控制台打印

I am Apple!
I am Banana!
I am Apple!

改进以后,假如此时  添加了一种新的水果   我们的工厂不需要进行改动

/**
* @author gege
* @Description
* @date 2019/3/14 17:16
*/
public class Grape implements Furits {
    public void descInfo() {
        System.out.println("I am Grape!");
    }
}
//假如需求变动  添加一个新的水果
@Test
public void update() {
    //此处客户端不需要自己动手创建实例  创建的过程交给工厂完成
    Furits furits = FuritsSimpleFactoryUpgrade.createFurits(Grape.class);
    furits.descInfo();


}
I am Grape!

案例:

JDK源码   Calendar. createCalendar()

LoggerFactory.getLogger();

小结

创建型模式对类的实例化过程进行了抽象,能够将对象的创建与对象的使用过程分离。

简单工厂模式又称为静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

简单工厂模式包含三个角色:工厂角色负责实现创建所有实例的内部逻辑;抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口;具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。

简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码将会非常复杂。

简单工厂模式适用情况包括:工厂类负责创建的对象比较少;客户端只知道传入工厂类的参数,对于如何创建对象不关心。

 

工厂方法模式

工厂方法模式(Fatory Method Pattern)是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节,而且加入新的产品符合开闭原则。

工厂方法模式主要解决产品扩展的问题,在简单工厂中,随着产品链的丰富,如果每个课程的创建逻辑有区别的话,工厂的职责会变得越来越多,有点像万能工厂,并不便于维护。根据单一职责原则我们将职能继续拆分,专人干专事。

 

代码演示

/**
* @author gege
* @Description 创建对象的接口
* @date 2019/3/14 18:00
*/
public interface IFuritsFactory {
    Furits createFurits();
}
/**
* @author gege
* @Description  实现工厂接口规范  专人干专事  该工厂只创建Apple
* @date 2019/3/14 18:01
*/
public class AppleFactory implements IFuritsFactory{
    public Furits createFurits() {
        return new Apple();
    }
}
/**
* @author gege
* @Description 实现工厂接口规范  专人干专事  该工厂只创建Banana
* @date 2019/3/14 18:04
*/
public class BananaFactory implements IFuritsFactory{
    public Furits createFurits() {
        return new Banana();
    }
}
/**
* @author gege
* @Description 实现工厂接口规范  专人干专事  该工厂只创建Grape
* @date 2019/3/14 18:05
*/
public class GrapeFactory implements IFuritsFactory {
    public Furits createFurits() {
        return new Grape();
    }
}
/**
* @author gege
* @Description 工厂方法的测试
* @date 2019/3/14 18:08
*/
public class IFuritsFactoryTest {


    @Test
    public void createFuritsTest(){
        AppleFactory appleFactory = new AppleFactory();
        Furits furits = appleFactory.createFurits();
        furits.descInfo();
    }
}

总结

工厂方法适用于以下场景:

1、创建对象需要大量重复的代码。

2、客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。

3、一个类通过其子类来指定创建哪个对象。

工厂方法也有缺点:

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

2、增加了系统的抽象性和理解难度。

抽象工厂模式

    什么是抽象工厂模式:就是将相同主题的工厂进行封装

     例如:生产一台PC机,使用工厂方法模式的话,一般会有cpu工厂,内存工厂,显卡工厂...但是使用抽象工厂模式的话,只有一个工厂就是PC工厂,但是一个PC工厂涵盖了cpu工厂,内存工厂,显卡工厂等要做的所有事;

  • 注意这里的“相同主题”的概念,表示的是同一个产品族,不能将cpu工厂,面粉工厂封装成一个工厂,因为他们不属于同一个产品族;

  • 另外,还有一个产品等级的概念,还是以生产PC机为例,所谓的产品等级指的是不同厂商生产的CPU,如Intel和AMD的CPU,他们是同一个产品等级,如果只涉及产品等级的话,是不需要应用抽象工厂模式,使用工厂方法模式即可;

  • 工厂方法模式解决的范畴是产品等级(AMD处理器,Intel处理器等);抽象工厂模式解决的范畴是产品族等级(联想PC、惠普PC等);

角色

  • 抽象工厂、具体工厂、抽象产品、具体产品、产品使用者

代码样例:

抽象的产品:给不同的产品族提供标准的接口

/**
* @author gege
* @Description 空调的产品接口
* @date 2019/3/15 9:58
*/
public interface IAirConditioner {
    void describeAirConditioner();
}


/**
* @author gege
* @Description 冰箱的产品接口
* @date 2019/3/15 10:00
*/
public interface IRefrigerator {
    void describeRefrigerator();
}

抽象工厂:能够提供所有产品的接口(属于同一个等级结构)

/**
* @author gege
* @Description  抽象的产品接口  创建产品
* @date 2019/3/15 10:01
*/
public interface ProductAbstractFactory {
    /**
     *
     * @return
     */
    IAirConditioner madeAirConditioner();


    /**
     *
     * @return
     */
    IRefrigerator madeRefrigerator();
}

具体工厂:每个具体工厂实现类

/**
* @author gege
* @Description 格力品牌 工厂实现类
* @date 2019/3/15 10:10
*/
public class GreeFactory implements ProductAbstractFactory {
    public IAirConditioner madeAirConditioner() {
        return new GreeAirConditioner();
    }


    public IRefrigerator madeRefrigerator() {
        return new GreeRefrigerator();
    }
}


/**
* @author gege
* @Description 美的产品的接口
* @date 2019/3/15 10:05
*/
public class MideaFactory implements ProductAbstractFactory {
    public IAirConditioner madeAirConditioner() {
        return new MideaAirConditioner();
    }


    public IRefrigerator madeRefrigerator() {
        return new MideaRefrigerator();
    }
}

产品的具体实现类

/**
* @author gege
* @Description  格力 空调产品的实现类
* @date 2019/3/15 10:11
*/
public class GreeAirConditioner implements IAirConditioner {
    public void describeAirConditioner() {
        System.out.println("i am Gree Air Conditioner");
    }
}

/**
* @author gege
* @Description 格力 冰箱产品实现类
* @date 2019/3/15 10:13
*/
public class GreeRefrigerator implements IRefrigerator {
    public void describeRefrigerator() {
        System.out.println("i am Gree Refrigerator");
    }
}

/**
* @author gege
* @Description 美的 空调产品实现类
* @date 2019/3/15 10:06
*/
public class MideaAirConditioner implements IAirConditioner {
    public void describeAirConditioner() {
        System.out.println("i am Midea Air Conditioner");
    }
}

/**
* @author gege
* @Description 美的 空调实现类
* @date 2019/3/15 10:07
*/
public class MideaRefrigerator implements IRefrigerator {
    public void describeRefrigerator() {
        System.out.println("i am Midea  Refrigerator");
    }
}

客户端

/**
* @author gege
* @Description
* @date 2019/3/15 10:14
*/
public class AbstractFactoryTest {


    @Test
    public void testAbstractFactory(){


        MideaFactory mideaFactory = new MideaFactory();


        IAirConditioner mideaAirConditioner = mideaFactory.madeAirConditioner();
        mideaAirConditioner.describeAirConditioner();


        IRefrigerator  mideaRefrigerator = mideaFactory.madeRefrigerator();
        mideaRefrigerator.describeRefrigerator();




        GreeFactory greeFactory = new GreeFactory();
        IAirConditioner greeAirConditioner =  greeFactory.madeAirConditioner();


        greeAirConditioner.describeAirConditioner();
        IRefrigerator greeRefrigerator = greeFactory.madeRefrigerator();
        greeRefrigerator.describeRefrigerator();


    }


}

缺点:

1、规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工 厂的接口。 

2、增加了系统的抽象性和理解难度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值