设计模式:Logback中的工厂方法
简介
如果创建某个对象需要大量重复代码,应用层不关注这个对象的创建细节,创建对象的过程可以推迟到子类实现,那么可以考虑使用工厂方法。工厂模式是通过简单工厂演化而来,与简单工厂相比,在加入新产品时符合开闭原则,扩展性更高。然而每增加一种产品,都需要创建对应的工厂类,会导致类数量过多,增加系统的复杂度。但这种基于产品和工厂的多态性设计,正是工厂方法的关键。
举例
继续我们在简单工厂中教学视频的例子。其实只需要将原来的工厂类拆分成两层,抽象工厂和具体产品工厂。
抽象工厂中只需要定义创建产品的抽象方法,它可以是一个接口,也可以是抽象类。
public abstract class VideoFactory {
public abstract Video getInstance();
}
产品的创建就交由具体的工厂类实现,每种产品都有自己的工厂。
public class JavaVideoFactory extends VideoFactory {
public Video getInstance() {
return new JavaVideo();
}
}
public class PythonVideoFactory extends VideoFactory {
public Video getInstance() {
return new PythonVideo();
}
}
这里的产品类和简单工厂中一致,一个基类,一些实现基类的具体产品类。
public abstract class Video {
private String name;
private String describe;
public abstract void produce();
}
public class JavaVideo extends Video {
public void produce() {
System.out.println("This is Java class.");
}
}
public class PythonVideo extends Video {
public void produce() {
System.out.println("This is python class.");
}
}
应用层只需要创建对应的工厂对象,调用统一的获取产品对象方法即可。
public class Test {
public static void main(String[] args) {
VideoFactory videoFactory = new JavaVideoFactory();
Video video = videoFactory.getInstance();
video.produce();
}
}
上文提过,工厂方法真正的实现了开闭原则。那我们就来需求扩展一下。加入现在又新增了一门MATLAB课程。(哈哈,原谅我对MATLAB的私心❤️
那么我们只需要创建新的MATLAB工厂类和MATLAB视频类分别继承其基类即可,完全无需修改已有类。
public class MatlabVideoFactory extends VideoFactory {
public Video getInstance() {
return new MatlabVideo();
}
}
public class MatlabVideo extends Video {
public void produce() {
System.out.println("This is MATLAB class.");
}
}
当应用层需要时,只需创建MatlabVideoFactory对象,并从其中获取即可。
public class Test {
public static void main(String[] args) {
VideoFactory videoFactory = new MatlabVideoFactory();
Video video = videoFactory.getInstance();
video.produce();
}
}
Logback中的工厂方法
Logback在创建Log时,使用的就是工厂方法。它的各个元素都是在同一个类sun.rmi.runtime的Log.java中用内部类实现,但这并不影响工厂方法的结构。它的抽象产品基类就是Log,其中一个产品实现类为LoggerLog,抽象工厂类为LogFactory,工厂实现类为LoggerLogFactory。另一对是LogStreamLog和LogStreamLogFactory。其中关键代码如下,为了更加易懂,我调整了一下源码顺序。
public abstract class Log {
... ...
public abstract void log(Level var1, String var2);
private interface LogFactory {
Log createLog(String var1, String var2, Level var3);
}
private static class LoggerLog extends Log {
public void log(Level var1, String var2) {
if (this.isLoggable(var1)) {
String[] var3 = Log.getSource();
this.logger.logp(var1, var3[0], var3[1], Thread.currentThread().getName() + ": " + var2);
}
}
}
private static class LoggerLogFactory implements Log.LogFactory {
public Log createLog(String var1, String var2, Level var3) {
Logger var4 = Logger.getLogger(var1);
return new Log.LoggerLog(var4, var3);
}
}
private static class LogStreamLog extends Log {
public void log(Level var1, String var2) {
if (this.isLoggable(var1)) {
String[] var3 = Log.getSource();
this.stream.println(unqualifiedName(var3[0]) + "." + var3[1] + ": " + var2);
}
}
}
private static class LogStreamLogFactory implements Log.LogFactory {
public Log createLog(String var1, String var2, Level var3) {
LogStream var4 = null;
if (var2 != null) {
var4 = LogStream.log(var2);
}
return new Log.LogStreamLog(var4, var3);
}
}
}
上一篇: 怎么调用别人接口?