简述
- 类型:结构型
- 目的:解决接口不兼容问题。
话不多说,看个案例吧。
优化案例
最初版v0
在真实的开发场景中,系统的每个模块都是分配给不同的团队或个人来开发的。这使得事前沟通变得尤为重要,且沟通问题也时有发生。现在公司有两个模块无法兼容,难道只能重写其中的一个吗?
class User {
String name;
String sex;
int age;
// 剩下的属性就不写了,都是废话没啥意义
public User(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
}
interface Filter {
List<User> findAll();
User findByName(String name);
}
class FilterImpl implements Filter { // Adaptee
List<User> users;
public FilterImpl(List<User> users) {
this.users = users;
}
public List<User> findAll() {
return users;
}
public User findByName(String name) {
if (name == null) throw new RuntimeException("请输入正确的ID!");
return (User) users.stream().filter(t -> name.equals(t.name)).findFirst().orElse(null);
}
}
interface JsonFilter { // Target
String allToJson();
String findByNameToJson(String id);
}
客户想要查询user
并且返回结果对象的Json
,只是当前的两个模块没法满足需求,如果不想修改这两个模块,我们如何实现两个模块功能的整合呢?
修改版v1(类适配器)
我们引入一个新的类作为适配器来适配原有的两个模块。
class User {
String name;
String sex;
int age;
// 剩下的属性就不写了,都是废话没啥意义
public User(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
}
interface Filter {
List<User> findAll();
User findByName(String name);
}
class FilterImpl implements Filter { // Adaptee
List<User> users;
public FilterImpl(List<User> users) {
this.users = users;
}
public List<User> findAll() {
return users;
}
public User findByName(String name) {
if (name == null) throw new RuntimeException("请输入正确的ID!");
return (User) users.stream().filter(t -> name.equals(t.name)).findFirst().orElse(null);
}
}
interface JsonFilter { // Target
String allToJson();
String findByNameToJson(String id);
}
class JsonFilterAdapter extends FilterImpl implements JsonFilter { // Adapter
public JsonFilterAdapter(List<User> users) {
super(users);
}
public String allToJson() {
List<User> users = super.findAll();
return new Gson().toJson(users);
}
public String findByNameToJson(String name) {
User user = super.findByName(name);
return new Gson().toJson(user);
}
}
代码修改后,我们来看一个客户端的使用案例。
class client {
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.add(new User("张三", "男", 19));
users.add(new User("李四", "男", 35));
users.add(new User("小红", "女", 21));
JsonFilterAdapter jfa = new JsonFilterAdapter(users);
String allUser = jfa.allToJson();
String user = jfa.findByNameToJson("张三");
System.out.printf("%s%n%s", allUser, user);
}
}
使用了类适配器确实让我们可以在不修改原有两个模块的情况下,以增加一个适配器类为代价整合两大模块。但,由于类适配器需要继承结构中的Adaptee
,且在客户端中的使用我们也能看出虽然我们能够调用继承的方法但没有直接使用。既然不使用为啥继承呢?
这就引出了新的问题:我们是否有必要使用继承来实现适配器。如答案是否,那不使用继承我们又如何设计适配器呢。这就得看接下来的优化了。
修改版v2(对象适配器)(推荐)
我们的问题,对象适配器可以解决!!!
class User {
String name;
String sex;
int age;
// 剩下的属性就不写了,都是废话没啥意义
public User(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
}
interface Filter {
List<User> findAll();
User findByName(String name);
}
class FilterImpl implements Filter { // Adaptee
List<User> users;
public FilterImpl(List<User> users) {
this.users = users;
}
public List<User> findAll() {
return users;
}
public User findByName(String name) {
if (name == null) throw new RuntimeException("请输入正确的ID!");
return (User) users.stream().filter(t -> name.equals(t.name)).findFirst().orElse(null);
}
}
interface JsonFilter { // Target
String allToJson();
String findByNameToJson(String id);
}
class JsonFilterAdapter implements JsonFilter { // 不在继承FilterImpl
private Filter filter; // 继承 → 聚合
public JsonFilterAdapter(List<User> users) {
this.filter = new FilterImpl(users);
}
public String allToJson() {
List<User> users = filter.findAll();
return new Gson().toJson(users);
}
public String findByNameToJson(String name) {
User user = filter.findByName(name);
return new Gson().toJson(user);
}
}
我们再看看客户端的调用代码。
class client {
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.add(new User("张三", "男", 19));
users.add(new User("李四", "男", 35));
users.add(new User("小红", "女", 21));
JsonFilterAdapter jfa = new JsonFilterAdapter(users);
String allUser = jfa.allToJson();
String user = jfa.findByNameToJson("张三");
System.out.printf("%s%n%s", allUser, user);
}
}
调用代码完全没有变化,但实际上已经无法在客户端中调用Filter中定义的方法了,这使得Adapter
类的都耦合度更低,有利于使用和维护。
总结
优点
- 使用适配器模式,不需要对于现有模块修改,符合开闭原则。
- 可以针对现有的模块创建多种多样的适配器,而客户端只需要调用适配器即可。让客户端与现有的多个模块解耦,防止日后模块修改时客户端也需要随之修改。
缺点
- 随着适配器类的加入,现有的系统将越发复杂。
- 增加了开发人员对于系统的理解难度。
适用场景
- 需要整合两个不兼容接口的场景。