工厂模式
简单工厂模式: 简单工厂模式(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、增加了系统的抽象性和理解难度。