静态工厂方法返回的对象所属的类,在编写包含该静态工厂方法的类时可以不必存在。这种灵活的静态工厂方法构成了服务提供者框架(Service Provider Framework)的基础,例如JDBC API。服务提供者框架是指这样一个系统:多个服务提供者实现一个服务(接口),系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来。

服务提供者框架中有四个重要的组件:

  • 服务接口(Service Interface),这是提供者实现的。如JDBC的Connection
  • 提供者注册API(Provider Registration API),这是系统用来注册提供者实现,让客户端访问它们的。如DriverManager.registerDriver
  • 服务访问API(Service Access API),是客户端用来获取服务的实例的。如DriverManager.get
  • 服务提供者接口(Service Provider Interface)这些提供者负责创建其服务实现的实例。这是可选的。如Driver

如果没有服务提供者接口,实现就按照类名称注册,并通过反射方式进行实例化。接口优于反射机制强烈建议使用服务提供者接口。

服务提供者框架模式有着无数种变体。例如,服务访问API可以利用适配器(Adapter)模式,返回比提供者需要的更丰富的服务接口。

服务提供者接口

package org.effectivejava.examples.chapter02.item01;

public interface Provider {
    Service newService();
}

服务接口

package org.effectivejava.examples.chapter02.item01;

public interface Service {
    // Service-specific methods go here
}

提供者注册API和服务访问API

package org.effectivejava.examples.chapter02.item01;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; public class Services {
private Services() {
} // Prevents instantiation (Item 4) // Maps service names to services
private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();
public static final String DEFAULT_PROVIDER_NAME = "<def>"; // Provider registration API
public static void registerDefaultProvider(Provider p) {
registerProvider(DEFAULT_PROVIDER_NAME, p);
} public static void registerProvider(String name, Provider p) {
providers.put(name, p);
} // Service access API
public static Service newInstance() {
return newInstance(DEFAULT_PROVIDER_NAME);
} public static Service newInstance(String name) {
Provider p = providers.get(name);
if (p == null)
throw new IllegalArgumentException(
"No provider registered with name: " + name);
return p.newService();
}
}

测试代码

package org.effectivejava.examples.chapter02.item01;

public class Test {
public static void main(String[] args) {
// Providers would execute these lines
Services.registerDefaultProvider(DEFAULT_PROVIDER);
Services.registerProvider("comp", COMP_PROVIDER);
Services.registerProvider("armed", ARMED_PROVIDER); // Clients would execute these lines
Service s1 = Services.newInstance();
Service s2 = Services.newInstance("comp");
Service s3 = Services.newInstance("armed");
System.out.printf("%s, %s, %s%n", s1, s2, s3);
} private static Provider DEFAULT_PROVIDER = new Provider() {
public Service newService() {
return new Service() {
@Override
public String toString() {
return "Default service";
}
};
}
}; private static Provider COMP_PROVIDER = new Provider() {
public Service newService() {
return new Service() {
@Override
public String toString() {
return "Complementary service";
}
};
}
}; private static Provider ARMED_PROVIDER = new Provider() {
public Service newService() {
return new Service() {
@Override
public String toString() {
return "Armed service";
}
};
}
};
}

《Effective Java》笔记-服务提供者框架的更多相关文章

  1. Effective Java笔记一 创建和销毁对象

    Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...

  2. effective java笔记之java服务提供者框架

    博主是一名苦逼的大四实习生,现在java从业人员越来越多,面对的竞争越来越大,还没走出校园,就TM可能面临失业,而且对那些增删改查的业务毫无兴趣,于是决定提升自己,在实习期间的时间还是很充裕的,期间自 ...

  3. Effective java笔记(二),所有对象的通用方法

    Object类的所有非final方法(equals.hashCode.toString.clone.finalize)都要遵守通用约定(general contract),否则其它依赖于这些约定的类( ...

  4. effective java笔记之单例模式与序列化

    单例模式:"一个类有且仅有一个实例,并且自行实例化向整个系统提供." 单例模式实现方式有多种,例如懒汉模式(等用到时候再实例化),饿汉模式(类加载时就实例化)等,这里用饿汉模式方法 ...

  5. Effective java笔记(一),创建与销毁对象

    1.考虑用静态工厂方法代替构造器 类的一个实例,通常使用类的公有的构造方法获取.也可以为类提供一个公有的静态工厂方法(不是设计模式中的工厂模式)来返回类的一个实例.例如: //将boolean类型转换 ...

  6. Effective java笔记(五),枚举和注解

    30.用enum代替int常量 枚举类型是指由一组固定的常量组成合法值的类型.在java没有引入枚举类型前,表示枚举类型的常用方法是声明一组不同的int常量,每个类型成员一个常量,这种方法称作int枚 ...

  7. Effective java笔记(三),类与接口

    类与接口是Java语言的核心,设计出更加有用.健壮和灵活的类与接口很重要. 13.使类和成员的可访问性最小化 设计良好的模块会隐藏起所有的实现细节,仅使用API与其他模块进行通信.这个概念称为信息隐藏 ...

  8. Effective java笔记5--通用程序设计

    一.将局部变量的作用域最小化      本条目与前面(使类和成员的可访问能力最小化)本质上是类似的.将局部变量的作用域最小化,可以增加代码的可读性和可维护性,并降低出错的可能性. 使一个局部变量的作用 ...

  9. Effective java笔记3--类和接口2

    三.接口优于抽象类 java提供两种机制,可以用来定义一个允许多个实现的类型:接口和抽象类.由于java只允许单继承,所以,抽象类作为类型定义受到了极大的限制. 已有的类可以很容易被更新,以实现新的接 ...

随机推荐

  1. NYOJ 12:喷水装置(二)(贪心,区间覆盖问题)

    12-喷水装置(二) 内存限制:64MB 时间限制:3000ms 特判: No 通过数:28 提交数:109 难度:4 题目描述: 有一块草坪,横向长w,纵向长为h,在它的橫向中心线上不同位置处装有n ...

  2. 【湖南师范大学2018年大学生程序设计竞赛新生赛 L】【HDOJ2476】【区间DP】

    https://www.nowcoder.com/acm/contest/127/L L 小小粉刷匠 题目描述 "lalala,我是一个快乐的粉刷匠",小名一边快活地唱着歌,一边开 ...

  3. 使用python查询某目录下所有‘jpg’结尾的图片文件

    调用os模块,先建立一个对目标目录的walk迭代器. 然后再对迭代器进行遍历,判断每个文件是否以'jpg'结尾. 若是,则输出. import os g = os.walk("G:" ...

  4. Mybaits代码生成使用

    https://jingyan.baidu.com/album/00a07f3869881082d028dc98.html PS:根据数据库中的表 生成代码

  5. 文件访问控制列表facl

    [root@bogon code]# getfacl a.c //获取文件a.c的文件访问控制列表 # file: a.c # owner: root # group: root user::rw- ...

  6. 使用netstat、lsof查看端口占用情况

    netstat netstat用来查看系统当前系统网络状态信息,包括端口,连接情况等,常用方式如下:   netstat -atunlp,各参数含义如下:   -t : 指明显示TCP端口 -u : ...

  7. IBM WebSphere MQ介绍安装以及配置服务详解

    首先介绍一下MQ MQ消息队列的简称是一种应用程序对应用程序的通信方法.说白了也就是通过队列的方式来对应用程序进行数据通信.而无需专用链接来链接它们. MQ的通讯方式 1.数据报的方式 Datagra ...

  8. APP前端易用性和UI测试

    移动APP使用场景的特点 1.屏幕小: 与Web系统相比,APP安装在手机端,展示屏幕只有几英寸,能够展示的信息就显得非常有限和珍贵,我们需要将有价值的信息放大,放在显眼的位置. 2.场景复杂化: 由 ...

  9. css易错点总结

    传智老师说:找工作要问调不调IE6,同样的工作待遇,如果不用调IE6开12000工资,要调IE6,直接加价到15000,因为调IE6能累死人,气死人. 行高要在字体后面,如下: 正确:font:400 ...

  10. Java单播、广播、多播(组播)---转

    一.通信方式分类 在当前的网络通信中有三种通信模式:单播.广播和多播(组播),其中多播出现时间最晚,同时具备单播和广播的优点. 单播:单台主机与单台主机之间的通信 广播:当台主机与网络中的所有主机通信 ...