概述
工厂,显而易见就是创建产品。在Java中,实例就是产品。我们通过创建工厂对象来生产实例而忽略创建细节。
简单工厂
定义:由一个工厂对象决定创建出哪一种产品类的实例
类型:创建型,但不属于GOF23种设计模式
优点:只需要传入一个正确的参数,就可以获取所需要的对象而无须知道其创建细节
缺点:工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,违背开闭原则
看个栗子
Video
public abstract class Video {
public abstract void produce();//抽象类方法
}
JavaVideo/PythonVideo
public class JavaVideo extends Video{
@Override
public void produce() {
System.out.println("Java Video");
}
}
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("Python Video");
}
}
工厂实现
public class VideoFactory {
public static Video getVideo(String type) {
if("java".equals(type)) {//匹配字符进行创建实例
return new JavaVideo();
}else if("python".equals(type)) {
return new PythonVideo();
}
return null;
}
}
测试类:
public static void main(String[] args) {
Video Java = VideoFactory.getVideo("java");//忽略创建实例细节,只需传入参数
Java.produce();
}
随着产品的扩展,VideoFactory需要增加判断逻辑,违背开闭原则。
我们通过反射的方法进行改进,增加可复用性。
public static Video getReflectVideo(Class klass) {
Video video =null;
try {
//获取类的全限定名
//根据反射基于类的全限定名创建此类
//根据newInstance()创建类的实例
video=(Video)Class.forName(klass.getName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return video;
}
工厂方法
定义:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类进行。父类工厂只指定规范,子类工厂负责生产具体产品。
一个类通过其子类来指定创建哪个对象
类型:创建型
优点:用户只需关心产品对应的工厂,无须关心创建细节;加入新产品符合开闭原则,提高可扩展性
缺点:类的个数容易过多,增加复杂度。
父类工厂提供规范
public abstract class VideoFactory {
//子类实现
public abstract Video getVideo();
}
子类工厂进行具体实现
public class PythonVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
}
public class JavaVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
}
测试类:
public static void main(String[] args) {
VideoFactory videoFactory = new JavaVideoFactory();//多态-子类转向父类
Video video = videoFactory.getVideo();
video.produce();
}
抽象工厂
定义:抽象工厂模式提供一个创建一系列相关或依赖对象的接口-无须指定它们具体的类
优点:工厂相关共有的优点;一个系列的产品族统一到一起创建
缺点:规定了所有可能被创建的产品集合,产品族中扩展新的产品有困难,需要修改抽象工厂的接口;增加了系统的抽象性和理解难度
类型:创建型
举个栗子解释上图,一个产品族可以看成是一个公司的一系列产品,比如格力公司的空调,洗衣机,风扇等就属于同一个产品族;而美的空调,海尔空调,格力空调就属于同一个产品等级结构,前面的工厂方法用来解决同一产品结构的创建,而抽象工厂用来创建产品族,这实际上也是抽象工厂和工厂方法最大的区别。
我们先创建一个抽象产品族(抽象产品族中不指定的哪家工厂的产品族,同时指定抽象的产品结构)
public interface ProductFactory {
//这条产品族中包含Fan和Air的产品等级结构
//产品族中指定产品结构
Fan getFan();
Air getAir();
}
具体的产品族实现工厂
//格力产品族
public class GeliProductFactory implements ProductFactory {
@Override
public Air getAir() {
return new GeliAir();
}
@Override
public Fan getFan() {
return new GeliFan();
}
}
//美的产品族
public class MeidiProductFactor implements ProductFactory {
@Override
public Air getAir() {
return new MeidiAir();
}
@Override
public Fan getFan() {
return new MeidiFan();
}
}
接下来是产品族中产品结构的抽象
//产品族在Air产品
public abstract class Air {
public abstract void produce();
}
//产品族中Fan产品
public abstract class Fan {
public abstract void produce();
}
//产品结构的具体实现
//美的空调
public class MeidiAir extends Air {
@Override
public void produce() {
System.out.println("生产美的空调");
}
}
//格力空调
public class GeliAir extends Air {
@Override
public void produce() {
System.out.println("生产格力空调");
}
}
//美的风扇
public class MeidiFan extends Fan {
@Override
public void produce() {
System.out.println("生产美的风扇");
}
}
//格力风扇
public class GeliFan extends Fan {
@Override
public void produce() {
System.out.println("生产格力风扇");
}
}
测试类:
public static void main(String[] args) {
ProductFactory factory = new GeliProductFactory();
Fan fan = factory.getFan();
Air air = factory.getAir();
air.produce();//打印结果:生产格力空调
fan.produce();//打印结果:生产格力风扇
}
抽象工厂方法在创建产品族上具有很好地扩展性,比如此时我想要加入新的产品族-海尔。只需要实现抽象产品族接口就可以,但是在扩展产品结构上不符合开闭原则,比如此时我想要在产品族上添加洗衣机这个产品,则需要改动抽象产品族这个接口