设计模式 之 适配器

适配器模式是一种常用的设计模式。

适配器模式的两种用法

第一种方式,是在我们写好一个接口和方法并编写调用后,出现了一种新的需求接口,为了使接口能够兼容,定义一个Adapter类。这种写法在做安卓开发兼容时经常用到。
plug_A_and_receptacle_A.png

假设我们已经写好了一个匹配的插座和插头,如上图所示。

假设现在又有了一个圆孔的插座(右),但是现在买回了一个方孔的插头(左)。为了使原本无法匹配的接口通用,我们可以使用这样一个适配器类(中),在适配器中进行接口的转换,如下图所示。
plug_B_and_receptacle_A.png

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class ReceptacleA {
public void work(PlugA plugA) {
plugA.plugRound();
System.out.println("插座工作");
}
}

class PlugA {
public void plugRound() {
System.out.println("插入圆孔插头");
}
}

class Adapter extends PlugA {
PlugB plugB;

Adapter(PlugB plugB) {
this.plugB = plugB;
}

@Override
public void plugRound() {
plugB.plugSquare();
}
}

class PlugB {
public void plugSquare() {
System.out.println("插入方孔插头");
}
}

class Test {
public static void testPlugA() {
ReceptacleA receptacleA = new ReceptacleA();
PlugA plugA = new PlugA();
receptacleA.work(plugA);
}

public static void testPlugB() {
ReceptacleA receptacleA = new ReceptacleA();
PlugB plugB = new PlugB();
Adapter adapter = new Adapter(plugB);
receptacleA.work(adapter);
}

public static void main(String[] args) {
testPlugA();
testPlugB();
}
}

代码运行结果:
adapter-java.png

第二种方式,是我们只希望实现接口中的部分方法时,通过定义一个抽象适配器类,再通过具体类继承来覆写其中的部分方法以达到继承接口部分方法的目的。

adapter2.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
interface Behaviours {
void run();
void swim();
void fly();
}

abstract class Animal implements Behaviours {
public void run(){}
public void swim(){}
public void fly(){}
}

class Dog extends Animal {
public void run() {
System.out.println("Dogs run");
}
public void swim() {
System.out.println("Dogs swim");
}
public static void main(String[] args){
Dog dog = new Dog();
dog.run();
dog.swim();
}
}

class Sparrow extends Animal {
public void fly() {
System.out.println("Sparrows fly");
}
public static void main(String[] args){
Sparrow sparrow = new Sparrow();
sparrow.fly();
}
}

项目实例

Eureka 项目

In eureka-core 客户端
com.netflix.discovery.shared.transport.EurekaHttpClient.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* Low level Eureka HTTP client API.
*
* @author Tomasz Bak
*/
public interface EurekaHttpClient {

EurekaHttpResponse<Void> register(InstanceInfo info);

EurekaHttpResponse<Void> cancel(String appName, String id);

EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id, InstanceInfo info, InstanceStatus overriddenStatus);

EurekaHttpResponse<Void> statusUpdate(String appName, String id, InstanceStatus newStatus, InstanceInfo info);

EurekaHttpResponse<Void> deleteStatusOverride(String appName, String id, InstanceInfo info);

EurekaHttpResponse<Applications> getApplications(String... regions);

EurekaHttpResponse<Applications> getDelta(String... regions);

EurekaHttpResponse<Applications> getVip(String vipAddress, String... regions);

EurekaHttpResponse<Applications> getSecureVip(String secureVipAddress, String... regions);

EurekaHttpResponse<Application> getApplication(String appName);

EurekaHttpResponse<InstanceInfo> getInstance(String appName, String id);

EurekaHttpResponse<InstanceInfo> getInstance(String id);

void shutdown();
}

In eureka-client-jersey2
com.netflix.discovery.shared.transport.jersey.AbstractJerseyEurekaHttpClient.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public abstract class AbstractJerseyEurekaHttpClient implements EurekaHttpClient {

private static final Logger logger = LoggerFactory.getLogger(AbstractJerseyEurekaHttpClient.class);
protected static final String HTML = "html";

protected final Client jerseyClient;
protected final String serviceUrl;

protected AbstractJerseyEurekaHttpClient(Client jerseyClient, String serviceUrl) {
this.jerseyClient = jerseyClient;
this.serviceUrl = serviceUrl;
logger.debug("Created client for url: {}", serviceUrl);
}

@Override
......

protected abstract void addExtraHeaders(Builder webResource);

private static Map<String, String> headersOf(ClientResponse response) {
......
}
}

In eureka-client
com.netflix.discovery.shared.transport.jersey.JerseyApplicationClient.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* A version of Jersey1 {@link EurekaHttpClient} to be used by applications.
*
* @author Tomasz Bak
*/
public class JerseyApplicationClient extends AbstractJerseyEurekaHttpClient {

private final Map<String, String> additionalHeaders;

public JerseyApplicationClient(Client jerseyClient, String serviceUrl, Map<String, String> additionalHeaders) {
super(jerseyClient, serviceUrl);
this.additionalHeaders = additionalHeaders;
}

@Override
protected void addExtraHeaders(Builder webResource) {
......
}
}

eureka-core 服务器端
PeerAwareInstanceRegistryImpl.java

1
2
3
4
@Singleton
public class PeerAwareInstanceRegistryImpl extends AbstractInstanceRegistry implements PeerAwareInstanceRegistry {
......
}

责任链加适配器模式
eureka-adapter-dutychain.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Singleton
@ProvidedBy(MyDataCenterInstanceConfigProvider.class)
public class MyDataCenterInstanceConfig extends PropertiesInstanceConfig implements EurekaInstanceConfig {

public MyDataCenterInstanceConfig() {
}

public MyDataCenterInstanceConfig(String namespace) {
super(namespace);
}

public MyDataCenterInstanceConfig(String namespace, DataCenterInfo dataCenterInfo) {
super(namespace, dataCenterInfo);
}

}

ProvidedBy是Guice的注解,表示
等同于

1
2
bind(MyDataCenterInstanceConfig.class)
.toProvider(MyDataCenterInstanceConfigProvider.class)
Docker词汇表 KDE Desktop Config

评论

You forgot to set the shortname for Disqus. Please set it in _config.yml.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×