Abstract Factory说明
图: UML类图和时序图【wiki】
在上述UML类图中,Client需要的类ProductA和ProductB对象不直接实例化ProductA1和ProductB1类。而是Client指AbstractFactory用于创建对象的接口,这使得Client独立于如何创建对象(哪些具体类被实例化)。本Factory1类实现了AbstractFactory通过实例的接口ProductA1和ProductB1类。
UML时序图显示了运行时的相互作用:在Client对象调用createProductA()的上Factory1对象,该对象创建并返回一个ProductA1对象。此后,Client电话createProductB()上Factory1,它创建并返回一个ProductB1对象。
Observer
图1: 垂直面互换
Observer 模式创造了垂直面的互换性,也就
是框架与应用类别的分合自如 ( 或称为 PnP) ,其依赖于 Observer 模式里的抽象
类别 ( 即接口 ) ,而达到「不知而亦能用」之效果。
Abstract Factory
而Abstract Factory是创造水平方向的互换性:
就是 Client 类别与 Server 类别之间的独立性。例如下图2 里,如果我们抽换掉 Server 应用类别时, Client 类别并不受影响,因为 Client 类别呼叫 Factory 抽象类别的函数去诞生Server 之对象。诞生完毕后, Client 类别呼叫 Server 抽象类别的函数去反向呼叫到 Server 应用类别之函数,就完成了 Client 与 Server 两个类别间之沟通了。由于我们抽换掉 Server 应用类别时,不会影响到 Client 类别,所以 Server 应用类别具有高度的抽换性
图2: 水平方向互换
抽象工厂模式基础(Factory method + Template method):
图3:Template Method与 Factory Metrhod 模式的组合
降低 Cleint 与 Server 之相依性
在上图里, ConcreteClient 类别的 FactoryMethod() 函数内:
obj = new ConcreteProduct();
它使用了 “ConcreteProduct” 字眼,这造成 ConcreteClient 与 ConcreteProduct
两个类别之间的高度相依性 (Dependency) 。此时,可以增添一个 ConcreteFactory
类别,将 ConcreteClient 与 ConcreteProduct 两类别分隔开来。如下图所示:
图4:AP端增加 ConcreteFactory
需要明确一个设计原则:针对接口(what)写程序,而不是实际内涵(how to).
从上图看出Client与 ConcreteFactory是有关联的,而后我们需要将Framework与AP的【变】与【不变】分离。
【变】与【不变】分离
图5:AF端增加Factory达到分离原则
package cn.pw.java.dp.absfactory;
public class AbsFactoryMain {
public static void main(String[] args) {
Client c = new ConcreteClient();
c.AnOperation();
}
}
//***** Framework *****
// Product
abstract class Product {
public void template_method() {
hook_method();
}
protected abstract void hook_method();
}
//Factory
abstract class Factory {
public abstract Product createProduct();
}
// Client
abstract class Client {
protected Factory fa;
private Product obj;
public void AnOperation() {
FactoryMethod();
obj = fa.createProduct();
obj.template_method();
}
//factory method为Factory赋值
public abstract void FactoryMethod();
}
//也可以返回Factory写法
abstract class Client2 {
protected Factory fa;
private Product obj;
public void AnOperation() {
fa = FactoryMethod();
obj = fa.createProduct();
obj.template_method();
}
public abstract Factory FactoryMethod();
}
//***** APP *****
class ConcreteProduct extends Product {
protected void hook_method() {
System.out.println("ConcreteProduct...");
}
}
class ConcreteFactory extends Factory {
public ConcreteProduct createProduct() {
return new ConcreteProduct();
}
}
class ConcreteClient extends Client {
public void FactoryMethod() {
fa = new ConcreteFactory();
}
}
Android中类似代码
Logger.java 【文件】
package com.android.camera.debug;
import com.android.camera.debug.Log.Tag;
import javax.annotation.ParametersAreNonnullByDefault;
/**
* Like {@link android.util.Log}.
*/
@ParametersAreNonnullByDefault
public interface Logger {
/**
* See {@link Log#d}.
*/
public void d(String msg);
//.....
/**
* See {@link Log#w}.
*/
public void w(String msg, Throwable tr);
/**
* Provides a Logger instance from a given Log tag.
*/
public interface Factory {
public Logger create(Tag tag);
}
}
Loggers.java
package com.android.camera.debug;
import com.android.camera.debug.Log.Tag;
import com.google.common.annotations.VisibleForTesting;
import javax.annotation.ParametersAreNonnullByDefault;
/**
* Set of commonly used loggers.
*/
@ParametersAreNonnullByDefault
public class Loggers {
/**
* This creates a factory that will eat all log input.
*/
public static Logger.Factory noOpFactory() {
return NoOpLoggerFactory.instance();
}
/**
* This creates a factory that will use the standard android static log
* methods.
*/
public static Logger.Factory tagFactory() {
return TagLoggerFactory.instance();
}
/**
* Creates a logger factory which always returns the given logger.
*/
public static Logger.Factory factoryFor(final Logger logger) {
return new Logger.Factory() {
@Override
public Logger create(Tag tag) {
return logger;
}
};
}
/**
* Creates loggers that eat all input and does nothing.
*/
private static class NoOpLoggerFactory implements Logger.Factory {
private static class Singleton {
private static final NoOpLoggerFactory INSTANCE = new NoOpLoggerFactory();
}
public static NoOpLoggerFactory instance() {
return Singleton.INSTANCE;
}
private final NoOpLogger mNoOpLogger;
public NoOpLoggerFactory() {
mNoOpLogger = new NoOpLogger();
}
@Override
public Logger create(Tag tag) {
return mNoOpLogger;
}
}
/**
* Creates loggers that use tag objects to write to standard android log
* output.
*/
private static class TagLoggerFactory implements Logger.Factory {
private static class Singleton {
private static final TagLoggerFactory INSTANCE = new TagLoggerFactory();
}
public static TagLoggerFactory instance() {
return Singleton.INSTANCE;
}
@Override
public Logger create(Tag tag) {
return new TagLogger(tag);
}
}
/**
* NoOp logger eats all input messages and does not display them.
*/
private static class NoOpLogger implements Logger {
@Override
public void d(String msg) {
}
//......
@Override
public void w(String msg, Throwable tr) {
}
}
/**
* TagLogger logger writes to the standard static log output with the given
* tag object.
*/
private static class TagLogger implements Logger {
private final Log.Tag mTag;
public TagLogger(Log.Tag tag) {
mTag = tag;
}
@Override
public void d(String msg) {
Log.d(mTag, msg);
}
@Override
public void e(String msg) {
Log.e(mTag, msg);
}
//.....
@Override
public void w(String msg, Throwable tr) {
Log.w(mTag, msg, tr);
}
}
}
SingleDeviceActions 【文件】
package com.android.camera.device;
import com.android.camera.async.Lifetime;
/**
* Device specific actions for opening and closing a device.
*/
public interface SingleDeviceActions<TDevice> {
/**
* Open the device represented by this instance. This should only
* be called if there is a reasonable expectation that the device is
* available and openable.
*
* It is possible for this to throw if there is a problem with the
* parameters or if the camera device determined to be un-openable.
*/
public void executeOpen(SingleDeviceOpenListener<TDevice> openListener,
Lifetime deviceLifetime) throws UnsupportedOperationException;
/**
* Close the device represented by this instance.
*
* It is possible for this to throw if there is a problem with the
* parameters used to create these actions.
*/
public void executeClose(SingleDeviceCloseListener closeListener, TDevice device)
throws UnsupportedOperationException;
}