This is the 13th day of my participation in the August More Text Challenge


1. Expansion of payment function

Due to the existence of Alipay and wechat, it has become very simple for the current system to do “online payment”. You can register an enterprise account on the corresponding platform, get the development documents, introduce the SDK package, and make some simple interface calls to complete the docking. This article takes “payment” as an example, skillfully uses “bridge mode” to carry on the function expansion.

When docking “payment business”, the requirements of company leaders are almost as follows: 1. The more payment platforms supported, the better; 2. The more payment methods supported, the better. Of course, the more the better. It will be easier for users to pay, and the leaders will not be happy.

To meet the needs of leaders means that there will be two dimensions of “payment function” expansion: 1. Expansion of payment platform, 2. Expansion of payment methods.

In order to meet the requirements of the leader, I decided to access wechat and Alipay, and then access other third parties, such as flash payment in cloud. In addition, AS long as the third party support payment method, I also access all, the goal is to make a “super payment”.

We use code to describe this process, and the class diagram design is as follows:Super simple class diagram, declare onePayPayment abstract class, define a variety of payment methods supported by the system, and then write two subclasses of Alipay and wechat to complete the docking of their respective platforms.

At first glance, there is no problem, but in actual development, there are problems. 1. Subclass is forced to implement wechat does not support “face payment” ah, how to do? We can only forced implementation in WeChatPay facePay () method, and throw an UnsupportedOperationException exception. What if wechat supports payment, but Alipay does not? We’re still going to do it. 2. It is inconvenient to extend payment methods. In Pay, it is responsible for defining payment methods and implementing subclasses, so it is very convenient to expand the payment platform, but it is very troublesome to expand payment methods.

OK, find the problem to solve the problem, we carry out the first optimization, the new class diagram design is as follows:Let’s take the class inheritance up a notch,PayThe payment platform and payment method are represented separately. The second layer is responsible for realizing platform functions, while the third layer is responsible for realizing payment methods corresponding to their respective platforms. As you can see, since wechat doesn’t support facial payments, it doesn’tWeChatFacePayThis class, cloud flash payment does not support Web site payment, so there is noQuickWebPayTo solve the problem of inflexibility of the first implementation.

But if you look at the structure of the system, do you see that there are a lot of classes? Yes, the class is inflated. Assuming that the system is connected to N payment platforms and supports M payment methods, then the number of classes is M*N, which is quite scary.

Can you optimize it a little bit? How about reducing the number of classes while still maintaining payment flexibility and scalability? The answer is yes, of course. We can abstract the payment method and strip out the implementation of the payment method. The payment platform class only relies on the abstraction of the payment method, and changes from inheritance to combination to improve flexibility.

The new class diagram is designed as follows:The number of classes is significantly reduced, but the functionality is not bad at all. It will be differentPayandPayTypeTogether, it can support nine payment implementations.

Abstract payment class Pay:

public abstract class Pay {
	protected PayMode payMode;// The payment method is abstract

	public Pay(PayMode payMode) {
		this.payMode = payMode;
	}

	protected abstract String platform(a);// Payment platform

	public final void pay(a){
		System.out.println("Use." + platform() + "The"+ payMode.mode()); }}Copy the code

Payment platforms: AliPay and WeChatPay.

public class AliPay extends Pay{

	public AliPay(PayMode payMode) {
		super(payMode);
	}

	@Override
	protected String platform(a) {
		return "Alipay"; }}public class WeChatPay extends Pay{

	public WeChatPay(PayMode payMode) {
		super(payMode);
	}

	@Override
	protected String platform(a) {
		return "WeChat"; }}Copy the code

Abstract PayMode for payment methods.

public interface PayMode {
	// Payment method
	String mode(a);
}
Copy the code

Three payment methods are realized:

public class WebPayMode implements PayMode {

	@Override
	public String mode(a) {
		return "Web payment"; }}public class MobilePayMode implements PayMode {

	@Override
	public String mode(a) {
		return "Mobile Payment"; }}public class FacePayMode implements PayMode {

	@Override
	public String mode(a) {
		return "Face pay"; }}Copy the code

The client calls like this:

public class Client {
	public static void main(String[] args) {
		Pay pay = new AliPay(new FacePayMode());
		pay.pay();
		pay = new AliPay(newMobilePayMode()); pay.pay(); Output: Use: Alipay face brush payment Use: Alipay mobile paymentCopy the code

See, the payment platform and payment method can be combined in any way, reducing the number of classes from M * N to M + N while satisfying the same function. This is bridge mode!

2. Definition of bridge mode

Decouple the abstraction from the implementation so that the two can vary independently.

Bridge pattern generic class diagram

  • Abstraction: An Abstraction character that defines the behavior of the character and keeps a reference to the implemented character.
  • RefinedAbstraction: RefinedAbstraction character, responsible for the abstraction character, and the correction of the abstraction character.
  • Implementor: Implements a role, interface, or abstract class that defines the properties and behavior of the role.
  • ConcreteImplementor: ConcreteImplementor responsible for concrete implementation of behavior.

Abstract roles refer to implementation roles, or the partial implementation of an abstract role is done by the implementation role. The focus of the bridge pattern is on “decoupling”, and the main focus of developers is how to decouple the two.

3. Advantages of bridge mode

1. Separation of abstraction and implementation, proposed to solve the disadvantages of inheritance. In bridge mode, implementations are not constrained by abstractions and are no longer tied to a fixed level of abstraction.

2. Good scalability. In the above example, it is very convenient to expand both the payment platform and the payment method.

3. Mask implementation details of high-level modules.

4. Reference scenarios in bridge mode

1. Consider bridging when you don’t want to use inheritance or when the structure of your class is not suitable for inheritance. Composition is better than inheritance.

2. If the system interfaces or abstract classes are unstable and may be frequently modified, you are advised to use the bridge mode.

3. A class has two or more dimensions that change independently and need to be extended.

5. To summarize

The core of the bridge mode is decoupling, which separates abstraction and implementation, and tries to encapsulate possible changing factors into the smallest and smallest logical unit to avoid risk diffusion. Inheritance is one of the three characteristics of the Java language, and it is a good design with many advantages. But its biggest disadvantage is “strong intrusion”, the parent class has methods, the subclass will also be forced to have, and a strong correlation between classes has been formed. Bridge model is used to solve the drawback of the “inheritance”, it describes a weak correlation between class and class, for places may change, it puts out from inheritance, if a subclass need this method, through the bridge in the past, for this method, the subclass if don’t want this method, also completely no problem. “Inheritance” + “bridge”, play to strengths and avoid weaknesses, use inheritance for functions that clearly won’t change, and bridge for functions that may change.