设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
有三个分类:
注:所有图片来源于网络,如有侵权立刻删除。
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
单例(Singleton)
//双重检查模式(DCL)
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){
}
public static Singleton getInstance() {
if (instance== null) {
synchronized (Singleton.class) {
if (instance== null) {
instance= new Singleton();
}
}
}
return singleton;
}
}
//静态内部类
public class Singleton {
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
//容器类实现
public class SingletonManager {
private static Map objMap = new HashMap();
private SingletonManager(){}
public static void registerService(String key,Object instance){
if (!objMap.containsKey(key)){
objMap.put(key,instance);
}
}
public static Object getInstance(String key){
return objMap.get(key);
}
}
系统只需要一个实例对象,调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。
通过Context获取系统级别的服务时,这些系统服务其实就是单例模式实现的,使用了容器实现的单例模式。
//使用LayoutInflater加载布局时
LayoutInflater.from(mContext).inflate(mLayoutId, null);
public static LayoutInflater from(Context context) {
//获取系统服务
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
//SYSTEM_SERVICE_FETCHERS为键值对容器,用来存储生成的SystemService
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
//SYSTEM_SERVICE_FETCHERS的初始化
private static final HashMap> SYSTEM_SERVICE_FETCHERS =
new HashMap>();
//LayoutInflater的创建加入在一个静态的代码块中进行注册服务,第一次加载该类的时候执行,并且只执行一次,保证实例的唯一性
static {
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}});
}
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
public class Director {
private Builder builder;
// 构造产品
public void construct() {
builder = new ConcreteBuilder();
builder.buildPart1();
builder.buildPart2();
}
}
abstract public class Builder {
// 构造"产品的Part1"的接口
public abstract void buildPart1();
// 构造"产品的Part2"的接口
public abstract void buildPart2();
// 返回产品
public abstract Product retrieveResult();
}
public class ConcreteBuilder {
private Product product = new Product();
public void buildPart1() {
// 参见产品的Part1
}
public void buildPart2() {
// 参见产品的Part2
}
public Product retrieveResult() {
return product;
}
}
public class Product {
// 产品组成部分...
}
如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
Retrofit.Builder就是一个简化版的建造者模式,Retrofit直接对应Product,并没有基于抽象Product进行扩展;Retrofit.Builder对应ConcreteBuilder,也没有基于抽象Builder进行扩展,同时省略了Director,并在Retrofit.Builder每个setter方法都返回自身,使得客户端代码可以链式调用,整个构建过程更加简单。
Retrofit retrofitBuilder = new Retrofit.Builder()
.baseUrl(NetworkConfig.getNewBaseUrl())
.client(mOkHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(CustomGsonConverterFactory.create())
.build();
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
//抽象工厂:提供“创建产品”的函数接口,并由其子类实现。
public interface Factory {
public Product newInstance() ;
}
//具体工厂:实现了抽象工厂提供的“创建产品”接口。
public class ConcreteFactory1 implements Factory {
public Product newInstance() {
return new ConcreteProduct1();
}
}
public class ConcreteFactory2 implements Factory {
public Product newInstance() {
return new ConcreteProduct2();
}
}
//抽象产品:提供了产品的公用方法函数
public interface Product {
}
//具体产品:实现了抽象产品的函数接口。
public class ConcreteProduct1 implements Product {
public ConcreteProduct1() {
// do something
}
}
public class ConcreteProduct2 implements Product {
public ConcreteProduct2() {
// do something
}
}
需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式。
Retrofit的CallAdapter创建使用了工厂模式。
//CallAdapter 为抽象产品
public interface CallAdapter {
Type responseType();
T adapt(Call call);
//allAdapter.Factory为抽象工厂类
abstract class Factory {
public abstract CallAdapter> get(Type returnType, Annotation[] annotations, Retrofit retrofit);
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
而它的具体工厂的实现类,已RxJava2CallAdapterFactory为例
public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
// 省略代码
@Override
public CallAdapter> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
// 省略代码
//此处的RxJava2CallAdapter即为具体产品类
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
isSingle, isMaybe, false);
}
private CallAdapter> getCallAdapter(Type returnType, Scheduler scheduler) {
// 省略代码
}
}
为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。
产品等级结构 :产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
产品族 :在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
抽象工厂模式与工厂方法模式的区别:
在工厂方法模式中,"抽象产品"只有一个,而在抽象工厂模式中,"抽象产品"有很多个!在工厂方法模式中,是由"具体工厂"决定返回哪一类产品;然后,抽象工厂中,是由"客户端"决定返回哪一类产品。
public interface Factory {
public ProductA newProductA();
public ProductB newProductB();
}
public class ConcreteFactory1 implements Factory {
public ProductA newProductA() {
return new ConcreteProductA1();
}
public ProductB newProductB();
return new ConcreteProductB1();
}
}
public class ConcreteFactory2 implements Factory {
public ProductA newProductA2() {
return new ConcreteProduct1();
}
public ProductB newProductB2();
return new ConcreteProduct1();
}
}
public interface ProductA {
}
public class ProductA1 implements ProductA {
}
public class ProductA2 implements ProductA {
}
public interface ProductB {
}
public class ProductB1 implements ProductB {
}
public class ProductB2 implements ProductB {
}
一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式。
例如一个文本编辑器和一个图片处理器,都是软件实体,但是Unix下的文本编辑器和Windows下的文本编辑器虽然功能和界面都相同,但是代码实现是不同的,图片处理器也有类似情况。也就是具有了共同的约束条件:操作系统类型。于是我们可以使用抽象工厂模式,产生不同操作系统下的编辑器和图片处理器
Retrofit中CallAdapter的使用的设计模式即为抽象工厂模式
public interface Converter {
T convert(F value) throws IOException;
//抽象工厂
abstract class Factory {
//Converter为抽象产品1
public Converter responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
//Converter, RequestBody>为抽象产品2
public Converter, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
//省略部分代码
}
}
这里以GsonConverterFactory为例子
//具体工厂
public final class GsonConverterFactory extends Converter.Factory {
// 省略代码
@Override
public Converter responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter> adapter = gson.getAdapter(TypeToken.get(type));
//GsonResponseBodyConverter<>为具体产品1
return new GsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter> adapter = gson.getAdapter(TypeToken.get(type));
//GsonRequestBodyConverter<>为具体产品2
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
又被称为"静态工厂方法模式"。它属于"创建模式"(创建对象的模式),并且是"工厂方法"模式的一种特殊实现。
工厂模式与简单工厂模式的区别
工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责哪一个产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
public class Factory {
public static Product newInstance() {
return new ConcreteProduct();
}
}
public abstract Product {
}
public class ConcreteProduct extends Product {
public ConcreteProduct() {}
}
工厂类负责创建的对象比较少;客户端只知道传入工厂类的参数,对于如何创建对象不关心。
Retrofit 中的Platform运用了简单工厂模式
//抽象产品
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
//工厂
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
//具体产品1
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
//具体产品2
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
//省略部分代码
}
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
public interface Prototype extends Cloneable {
Prototype clone();
}
public class ConcretePrototype implements Prototype {
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
public class Client {
private Prototype prototype;
public void operation(Prototype example) {
Prototype p = (Prototype) example.clone();
}
}
性能优良,内存二进制的拷贝,比直接new一个对象性能好很多。
构造函数不会执行,缺少相应约束
Retrofit中的用于发起网络请求的OkHttpCall就使用了原型模式,优势在于使用原型模式的二进制的copy性能较好,当由大量网络请求时,该优势就能更明显的体现出来了。
final class OkHttpCall implements Call {
//省略部分代码
@SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
@Override public OkHttpCall clone() {
return new OkHttpCall<>(serviceMethod, args);
}
//省略部分代码
}