Design Patterns | VIII adapter mode (class adapters, object adapters, two-way adapter) [AdapterPattern]

Adapter mode

Source: https://github.com/GiraffePeng/design-patterns

1. Definitions

Convert the interface of a class into another interface clients expect that those classes otherwise because of incompatible interfaces can not work together to work together.
Adapter mode is divided into mode-based structural and structural objects two modes, coupling between the former than the latter category, a programmer is required and the internal structure of the conventional component library related components, it is relatively seldom used some.

2, application scenarios

  • Previously developed systems exist to meet the functional requirements of the new class system, but its interface is inconsistent with the new system interface.
  • Using components provided by third parties, but the component interface definitions and requirements of different interfaces define your own.
  • Design Patterns adapter model is not considered in the design phase of the software, along with software maintenance, due to the different products, does not
    cause the solution under similar functions and the interface is not the same case with the manufacturers.

3, mode structure

Adapter mode (Adapter) contains the following major role.

  • Target (Target) Interface: the current system of business expected interface, which can be abstract classes or interfaces.
  • Fitter (the Adaptee) Class: it is being accessed and an interface component adapted existing component library.
  • Adapter (Adapter) class: it is a converter, by inheritance or referenced objects fitter and fitter conversion interface into the target interface, according to the destination interface to allow customers to access the adapter's format.

4, application examples

4.1, an integrated three-way SMS (basic function service)

In the actual development, often encounter docking outside party service, such as: storage, messaging and other basic services. Then tripartite platform may provide api interface to let ourselves assemble data packets to the request, but also provide us with the appropriate SDK SDK let us rely just call interface within the same project to use three-way service.
Here we use to send text messages to simulate three-way adapter mode.
Normally, if the tripartite platform provided for the api interface needs to call us, so we can write.
As a basic function, aspects of the service call, it can serve as an interface or tools. This example embodiment is the use as an interface, the interface is equivalent to the target interface in the above-described configuration mode, the system is expected current service interface.

/**
 * 短信发送接口声明
 */
public interface SmsService {

	/**
	 * 短信发送
	 * @param content 短信的内容
	 * @return 是否发送成功
	 */
	public Boolean sendSms(String content);
}

Create an adapter class

public class SmsServiceImpl implements SmsService{

	
	private String smsKey = "ssajwi12wwe";
	
	private String templateId = "tejsi1221s";
	
	@Override
	public Boolean sendSms(String content) {
		//处理短信发送逻辑 
		CloseableHttpClient httpclient = HttpClients.createDefault(); 
		HttpPost httpPost = new HttpPost("三方短信平台接口地址");
		// 创建参数队列     
        List<NameValuePair> formparams = new ArrayList<NameValuePair>();   
        formparams.add(new BasicNameValuePair("smsKey", smsKey));   
        formparams.add(new BasicNameValuePair("templateId", templateId)); 
        UrlEncodedFormEntity uefEntity;
        try {
			uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
			httpPost.setEntity(uefEntity); 
			CloseableHttpResponse execute = httpclient.execute(httpPost);
			HttpEntity entity = execute.getEntity();
		} catch (Exception e) {
			e.printStackTrace();
		}   
		System.out.println("短信发送成功");
		return true;
	}

}

Because the butt for the api provided, so the use of http request to call interface tripartite platform, the implementation class in fact equivalent adapter class, but who fit class (existing component interface component library is accessed and adapted in) is http protocol for the external interface exposed Bale.

In order to better reflect the adapter mode, if the service we provide tripartite platform is the use of embedded SDK method, we need to use the SDK which provides services to complete the call, we have to transform our code, to simulate scenarios under SDK use of an adapter.
First, a simulation method in the SDK, which is provided by a tripartite platform.

/**
 * 适配者类,(需要被进行适配的类) 
 */
public class SmsSDK {
	
	public Boolean sendSms(String smsKey,String templateId,String content) {
		//这里不探究SDK中封装的方法是如何完成短信发送的,只是模拟
		System.out.println("发送短信成功");
		return true;
	}
}

Combined with just SmsService interface to create a new implementation class, namely adapter class

/**
 * 适配器,将原有的sdk需要传入的smsKey与templateId给自行适配。对外暴露的接口,只传入短信内容即可。
 * 这种方式也符合了迪米特原则,即最少知识原则。
 */
public class SmsSDKServiceImpl implements SmsService{
	
	private SmsSDK smsSDK;
	
	private String smsKey = "2121sjww";
	
	private String templateId = "2j1wiqsw";
	
	public SmsSDKServiceImpl() {
		smsSDK = new SmsSDK();
	}
	
	@Override
	public Boolean sendSms(String content) {
		Boolean sendSms = smsSDK.sendSms(smsKey, templateId, content);
		return sendSms;
	}
}

In this way the system is to use text messaging function, only need to pass the message content without the need to pass additional parameters of concern.
The above scenarios are directed to: the use of third-party assembly, but using different adapter mode component interface definitions and requirements of their interface definitions situation.

4.2, log function

This example is for another application adapter scenario, namely the presence of previously developed system meets the functional requirements of the new class system, but its interface is inconsistent with the new system interface. The actual scenario: the current account password set by the method, and now want to add to the default Bintang according to openId micro letter, the business end only need to pass openId you can login. Then we can use the adapter mode, openId queries to meet user data assembled into the original landing interface parameters to achieve the landing.

Creating the ginseng

/**
 * 创建登陆接口入参值
 */
public class TokenEndpointEntity {

	private String grant_type;
	
	private String username;
	
	private String password;

	public String getGrant_type() {
		return grant_type;
	}

	public void setGrant_type(String grant_type) {
		this.grant_type = grant_type;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
}

Creating a landing ginseng

/**
 * 创建登陆接口 返回实体
 */
public class AccessToken {

	private String access_token;
	
	private String token_type;
	
	private String refresh_token;
	
	private Long expires_in;
	
	private String scope;

	public String getAccess_token() {
		return access_token;
	}

	public void setAccess_token(String access_token) {
		this.access_token = access_token;
	}

	public String getToken_type() {
		return token_type;
	}

	public void setToken_type(String token_type) {
		this.token_type = token_type;
	}

	public String getRefresh_token() {
		return refresh_token;
	}

	public void setRefresh_token(String refresh_token) {
		this.refresh_token = refresh_token;
	}

	public Long getExpires_in() {
		return expires_in;
	}

	public void setExpires_in(Long expires_in) {
		this.expires_in = expires_in;
	}

	public String getScope() {
		return scope;
	}

	public void setScope(String scope) {
		this.scope = scope;
	}
	
	
	public AccessToken() {
		super();
	}
	
	public AccessToken(String access_token, String token_type, String refresh_token, Long expires_in, String scope) {
		super();
		this.access_token = access_token;
		this.token_type = token_type;
		this.refresh_token = refresh_token;
		this.expires_in = expires_in;
		this.scope = scope;
	}

	static class AccessTokenBuilder{
		private String access_token;
		
		private String token_type;
		
		private String refresh_token;
		
		private Long expires_in;
		
		private String scope;
		
		public AccessTokenBuilder access_token(String access_token) {
			this.access_token = access_token;
			return this;
		}
		
		public AccessTokenBuilder token_type(String token_type) {
			this.token_type = token_type;
			return this;
		}
		
		public AccessTokenBuilder refresh_token(String refresh_token) {
			this.refresh_token = refresh_token;
			return this;
		}
		
		public AccessTokenBuilder expires_in(Long expires_in) {
			this.expires_in = expires_in;
			return this;
		}
		
		public AccessTokenBuilder scope(String scope) {
			this.scope = scope;
			return this;
		}
		
		public AccessToken build() {
			return new AccessToken(access_token, token_type, refresh_token, expires_in, scope);
		}
	}
	
	public static AccessTokenBuilder builder() {
		return new AccessTokenBuilder();
	}
}

The above classes which use the builder pattern to provide analog functions @Builder comment lombok realization of benefits that do not come in a set assignment method invocation property line by line when assigned to a class, you can use static methods of the class assignments directly, instantiated without explicit object position.
To AccessToken for example, the transformation of the former how we need to assign an assignment, or set by the constructor method.

AccessToken accessToken = new AccessToken();
accessToken.setScope("service");
accessToken.setToken_type("");

After the transformation can be so assigned, a lot of convenience.

AccessToken accessToken = AccessToken.builder().access_token(String.valueOf(UUID.randomUUID())).expires_in(1000L)
	.refresh_token(String.valueOf(UUID.randomUUID())).scope("service").token_type("barear").build()

Return to the topic, we continue to create original login interfaces

//声明登陆信息操作接口
public interface LoginService {
	
	AccessToken login(TokenEndpointEntity tokenEndpointEntity);
}

Creates its implementation class

public class LoginServiceImpl implements LoginService {

	@Override
	public AccessToken login(TokenEndpointEntity tokenEndpointEntity) {
		// 交互数据库取出用户信息进行比对
		
		// 拼装返回数据
		return AccessToken.builder().access_token(String.valueOf(UUID.randomUUID())).expires_in(1000L)
				.refresh_token(String.valueOf(UUID.randomUUID())).scope("service").token_type("barear").build();
	}
}

Then a original login function is realized, then we want to comply with the principle of opening and closing, without modifying the original code base up new features were completed, namely through micro letter openId login. According Dependency Inversion principle, we should oriented programming interface, let's create target interface

//声明登陆适配器接口
public interface LoginAdapter {
	
	/**
	 * 登陆
	 * @param onlyFlag 传入 唯一标识 比如微信的openId
	 * @return
	 */
	AccessToken login(String onlyFlag);
}

Creating its implementation class, namely adapter class

public class LoginAdapterForWechat extends LoginServiceImpl implements LoginAdapter{

	@Override
	public AccessToken login(String onlyFlag) {
		//根据onlyFlag(即openId)去查询 用户信息
		//根据查询出来的数据 组装TokenEndpointEntity
		TokenEndpointEntity tokenEndpointEntity = new TokenEndpointEntity();
		tokenEndpointEntity.setUsername("");
		tokenEndpointEntity.setPassword("");
		tokenEndpointEntity.setGrant_type("password");
		return login(tokenEndpointEntity);
	}
}

1 and various examples herein, using the example of a structure of the object adapter (reference method is adapted by the object, call the object), the exemplary embodiment uses a second-class adapter i.e., through inheritance is adapted player object directly call the parent method to complete the adaptation.

If there are other methods require landing approach, such as QQ, Sina and other third-party landing, into the reference conditions are satisfied, the interface method declarations, the adapter can be done by deriving new implementation class, meaning it can be adapted according to the class, adapter there are more to meet the different scenes.

5, expand

In order to meet the flexibility of the adapter may occur under certain scenarios adapter calls a target object, the target object may in turn call the adapter case occurs, then we need to complete the two-way adapter.
Create a target interface

//目标接口
public interface TwoWayTarget {
	public void request();
}

Create a target interface implementation class

//目标实现
public class TargetRealize implements TwoWayTarget{

	@Override
	public void request() {
		System.out.println("目标代码被调用!");
	}
}

Creating an interface adapter

//适配者接口
public interface TwoWayAdapter {
	public void specificRequest();
}

Create a class that implements an interface adapter

//适配者实现
public class AdapteeRealize implements TwoWayAdapter{

	@Override
	public void specificRequest() {
		System.out.println("适配者代码被调用!");
	}
}

Key: Create a two-way adapter class holds a reference adapter and target class, and implemented in both sides of the interface.

//双向转换适配器
public class TwoWayTransformationAdapter implements TwoWayTarget, TwoWayAdapter {

	private TwoWayTarget target;
	private TwoWayAdapter adapter;

	public TwoWayTransformationAdapter(TwoWayTarget target) {
		this.target = target;
	}

	public TwoWayTransformationAdapter(TwoWayAdapter adapter) {
		this.adapter = adapter;
	}

	@Override
	public void specificRequest() {
		target.request();
	}

	@Override
	public void request() {
		adapter.specificRequest();
	}
}

FIG bidirectional adapter class as follows:
Here Insert Picture Description

6, the advantages and disadvantages

The main advantage of this mode is as follows.

  • The client can transparently invoke the target through the interface adapter.
  • Multiplexed with the existing class, the programmer need not modify the original code reuse existing classes fitter.
  • The target class and the class of decoupled fitter solve the problem of the target class and the class interface adapter are inconsistent.

The main disadvantages are as follows:

  • Adapter writing process takes full account, it may increase the complexity of the system.
  • Increase the difficulty of reading the code, reduce code readability, excessive use of adapter system code will become cluttered.
Published 21 original articles · won praise 2 · Views 7493

Guess you like

Origin blog.csdn.net/qq_35551089/article/details/101520398