学习设计模式不光要学习设计模式的思想,还要去深入理解,为什么要用这个设计模式。
如何深入理解?读优秀的框架代码,看别人代码,了解它们的使用场景。 - - - 博主老师(感谢他)
本文先介绍了抽象工厂模式的概念及简单实现。再介绍了netty中对抽象工厂模式的实现。最后总结了一点点思考。
抽象工厂模式
概念
定义:为创建一组相关或相互依赖的对象提供一个接口,而不需要指定它们的具体实现类
怎么理解呢?例如所有的车有轮胎、制动系统等,但不同系列的车轮胎和制动系统又不一样。这里的轮胎、制动系统指的就是上面定义中所说的“一组相关的对象”。我们要提供的抽象工厂,将会帮我们创建这些产品。
实现
实现上面所说的轮胎、制动系统的例子
制动系统
public interface IBrake {
void brake();
}
public class ABrake implements IBrake {
@Override
public void brake() {
System.out.println("A级制动系统");
}
}
public class BBrake implements IBrake {
@Override
public void brake() {
System.out.println("B级制动系统");
}
}
轮胎
public interface ITire {
void tire();
}
public class ATire implements ITire {
@Override
public void tire() {
System.out.println("A级轮胎");
}
}
public class BTrie implements ITire {
@Override
public void tire() {
System.out.println("B级轮胎");
}
}
工厂
public interface Factory {
ITire createTrie();
IBrake createBrake();
}
public class AFactory implements Factory {
@Override
public ITire createTrie() {
return new ATire();
}
@Override
public IBrake createBrake() {
return new ABrake();
}
}
public class BFactory implements Factory {
@Override
public ITire createTrie() {
return new BTrie();
}
@Override
public IBrake createBrake() {
return new BBrake();
}
}
测试类
public static void main(String[] args) {
Factory factory = new AFactory();
factory.createBrake().brake();
factory.createTrie().tire();
Factory factory2 = new BFactory();
factory2.createBrake().brake();
factory2.createTrie().tire();
}
输出
A级制动系统
A级轮胎
B级制动系统
B级轮胎
其实非常简单,我们可以看到,A工厂创建出来的都是A系列产品,B工厂创建出来的都是B系列产品。
netty 中的抽象工厂模式
netty中ByteBufAllocator 是netty的内存管理器,负责分配所有的ByteBuf类型的内存。
类结构图(图片来自网络):
这里ByteBufAllocator就是我们的抽象工厂,PooledByteBBufAllocator和UnpooledByteBufAllocator就是具体的工厂。
这里比较有意思的是netty给 ByteBufAllocator抽象工厂设置了个默认工厂
public interface ByteBufAllocator {
ByteBufAllocator DEFAULT = ByteBufUtil.DEFAULT_ALLOCATOR;
}
byteBufUtil根据allocType得到默认的工厂。
public final class ByteBufUtil {
static final ByteBufAllocator DEFAULT_ALLOCATOR;
static {
String allocType = SystemPropertyUtil.get(
"io.netty.allocator.type", PlatformDependent.isAndroid() ? "unpooled" : "pooled");
allocType = allocType.toLowerCase(Locale.US).trim();
ByteBufAllocator alloc;
if ("unpooled".equals(allocType)) {
alloc = UnpooledByteBufAllocator.DEFAULT;
logger.debug("-Dio.netty.allocator.type: {}", allocType);
} else if ("pooled".equals(allocType)) {
alloc = PooledByteBufAllocator.DEFAULT;
logger.debug("-Dio.netty.allocator.type: {}", allocType);
} else {
alloc = PooledByteBufAllocator.DEFAULT;
logger.debug("-Dio.netty.allocator.type: pooled (unknown: {})", allocType);
}
}
具体的工厂
public class PooledByteBufAllocator extends AbstractByteBufAllocator implements ByteBufAllocatorMetricProvider {
@Override
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
PoolThreadCache cache = threadCache.get();
PoolArena<byte[]> heapArena = cache.heapArena;
final ByteBuf buf;
if (heapArena != null) {
buf = heapArena.allocate(cache, initialCapacity, maxCapacity);
} else {
buf = PlatformDependent.hasUnsafe() ?
new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity) :
new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
}
return toLeakAwareBuffer(buf);
}
@Override
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
PoolThreadCache cache = threadCache.get();
PoolArena<ByteBuffer> directArena = cache.directArena;
final ByteBuf buf;
if (directArena != null) {
buf = directArena.allocate(cache, initialCapacity, maxCapacity);
} else {
buf = PlatformDependent.hasUnsafe() ?
UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) :
new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}
return toLeakAwareBuffer(buf);
}
}
public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator implements ByteBufAllocatorMetricProvider {
@Override
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
return PlatformDependent.hasUnsafe() ?
new InstrumentedUnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity) :
new InstrumentedUnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
}
}
@Override
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
final ByteBuf buf;
if (PlatformDependent.hasUnsafe()) {
buf = noCleaner ? new InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf(this, initialCapacity, maxCapacity) :
new InstrumentedUnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
} else {
buf = new InstrumentedUnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}
return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
}
节选了具体工厂的部分代码。有池的和无池的都需要提供 在堆和直接内存上分配ByteBuf的方法。但他们各自的实现确实不相同的。而客户端在调用的时候,只要调方法,不需要感知他们的实现。
思考
个人认为抽象工厂模式只要把握住:“一组相关的对象提供一个接口”这句话就行了。意思就是抽象A类需要abcd四个方法。子类A1和子类A2都有abcd方法,但是他们的实现可能不一样。
这个时候就可以用抽象工厂。