设计模式之适配器模式
适配器模式:
适配器模式(Adapter Pattern)是一种结构设计模式,用于将一个类的接口转换成客户端期望的另一个接口。它允许已存在的类协同工作而无需修改其源代码,通常用于解决接口不兼容性的问题。
适配器模式的使用场景包括:
- 系统升级和集成: 当你需要将旧系统集成到新系统中,但新系统期望的接口不与旧系统匹配时,可以使用适配器模式。
- 第三方库使用: 当你需要使用一个第三方库或组件,但其接口与你的应用程序不匹配时,可以创建适配器以使两者协同工作。
- 接口的复用: 当你希望重用一些现有的类,但它们的接口与你的需求不符时,适配器允许你在不修改现有代码的情况下使用这些类。
实现方式
适配器模式通常涉及以下角色:
- 目标接口(Target Interface):这是客户端所期望的接口。客户端代码通过与目标接口交互,但它需要一个适配器以便与特定的现有类(被适配的类)协同工作。
- 适配器(Adapter):适配器是一个类,它实现了目标接口并包含对被适配的类的引用。适配器的工作是将目标接口方法调用转换成被适配类的方法调用,从而实现目标接口。
- 被适配的类(Adaptee):这是需要与目标接口协同工作的现有类。这个类可能不实现目标接口,也许由于接口不兼容性而不能直接与客户端代码一起使用。
适配器模式可以有两种实现方式:类适配器和对象适配器。它们在适配器与被适配对象之间的关系不同。
-
类适配器:
- 在类适配器中,适配器类继承了被适配类并同时实现了目标接口。
- 这意味着适配器类不仅可以访问被适配类的方法,还可以通过实现目标接口来适配客户端代码。
// 类适配器 class Adapter extends Adaptee implements Target { public void request() { specificRequest(); // 调用被适配类的方法 } }
类适配器的优点是它可以访问被适配类的方法,但缺点是它需要多重继承或支持多重继承的语言。
-
对象适配器:
- 在对象适配器中,适配器类包含一个对被适配类的引用。
- 它实现了目标接口并将目标接口的方法委派给被适配类的实例。
// 对象适配器 class Adapter implements Target { private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } public void request() { adaptee.specificRequest(); // 委派给被适配类的实例 } }
对象适配器的优点是它不需要多重继承,因此更灵活,可以适配不同的被适配类。
推荐使用对象适配器
--------------------------------------------------------------------------------------------------------- // 目标接口 interface Target { void request(); } --------------------------------------------------------------------------------------------------------- // 被适配的类 class Adaptee { public void specificRequest() { System.out.println("新方法"); } } --------------------------------------------------------------------------------------------------------- // 适配器 class Adapter implements Target { private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } @Override public void request() { adaptee.specificRequest(); } } --------------------------------------------------------------------------------------------------------- public class Client { public static void main(String[] args) { Adaptee adaptee = new Adaptee(); Target adapter = new Adapter(adaptee); //此时adapter可以传参给需要Target类型的方法调用,再调用request()方法时,使用的不是原本Target的,而是Adapter的。 } }
补充:
缺省适配器
"缺省适配器"
是一种设计模式,也叫做 “默认适配器” 或 “空适配器”,它通常用于面向接口的编程中。这个模式的主要目的是允许一个接口中的方法在不需要实现所有方法的情况下,被子类实现。这对于大型接口而言尤为有用,因为子类可以只选择实现它们关心的方法。
缺省适配器的主要特点包括:
-
提供默认实现:缺省适配器为接口中的每个方法提供了默认的空实现,或者提供了一些通用行为,使得子类可以选择性地覆盖它们。
-
允许子类选择性实现:子类可以根据需要选择性地实现接口中的方法,而不必实现每个方法。这使得接口更加灵活。
-
减少冗余代码:使用缺省适配器可以减少重复代码的编写,因为子类只需要实现其关注的方法,而不必提供空实现。
-
提高可维护性:通过提供缺省适配器,接口可以在不破坏现有子类的情况下进行扩展。这提高了接口的可维护性。
//一个接口 MyInterface: public interface MyInterface { void method1(); void method2(); }
//一个缺省适配器类 MyInterfaceAdapter: public abstract class MyInterfaceAdapter implements MyInterface { @Override public void method1() { // 默认的空实现 } @Override public void method2() { // 默认的空实现 } }
//现在,如果你想实现 MyInterface,但只关心 method1,你可以创建一个类并继承 MyInterfaceAdapter,然后只实现 method1: public class MyImplementation extends MyInterfaceAdapter { @Override public void method1() { // 实现 method1 的代码 } // method2 不需要实现 }
双向适配器
双向适配器
,用于将两个不兼容的接口或类连接在一起,以使它们可以相互通信。在Java中,你可以使用适配器模式来实现双向适配器。
-
下面是一个简单的Java示例,演示如何创建一个双向适配器。
假设你有两个接口,一个是
Target
,另一个是Adaptee
,它们分别如下:// Target 接口 public interface Target { void request(); } // Adaptee 接口 public interface Adaptee { void specificRequest(); }
现在,你想要创建一个双向适配器,使
Target
可以调用Adaptee
的方法,同时Adaptee
也可以调用Target
的方法。你可以创建一个实现这两个接口的适配器类,如下所示:public class TwoWayAdapter implements Target, Adaptee { private Adaptee adaptee; private Target target; public TwoWayAdapter(Adaptee adaptee, Target target) { this.adaptee = adaptee; this.target = target; } @Override public void request() { adaptee.specificRequest(); } @Override public void specificRequest() { target.request(); } }
在这个示例中,
TwoWayAdapter
实现了Target
和Adaptee
接口,并在其方法中进行双向适配。当request
方法被调用时,它会调用Adaptee
的specificRequest
方法,而当specificRequest
方法被调用时,它会调用Target
的request
方法。现在,你可以使用这个双向适配器将两个不兼容的接口连接在一起,使它们可以相互通信:
Adaptee adaptee = new SomeAdaptee(); Target target = new SomeTarget(); TwoWayAdapter adapter = new TwoWayAdapter(adaptee, target); // 使用适配器从Target调用Adaptee的方法 target.request(); // 使用适配器从Adaptee调用Target的方法 adaptee.specificRequest();
这个示例演示了如何使用双向适配器模式来连接
Target
和Adaptee
接口,使它们可以互相调用彼此的方法。