Blog: bugstack.cn

Precipitation, share, grow, let yourself and others can gain something! 😄

One, foreword

Why is there so much ifelse in your code

The same business, the same function, how can you write so many ifelse. Most of the time, some programmers who have just entered the enterprise from the campus, or some of them jump from small companies to large enterprises, when they first undertake business needs, they are often immature in coding, and often write requirements to the end. The initial implementation was fast, but later maintenance and extension were painful. The more readable a piece of code is, the higher the maintenance cost will be.

Design patterns can help you improve your code

A lot of times you write ifelse without thinking about design pattern optimization, like; Different interfaces of similar services for packaging, construction of different combinations of similar materials, a variety of prize combinations of marketing factories and so on. They can turn your code into a set of classes and object-oriented implementations where you would normally use if judgments.

How do you integrate design patterns with actual development

Think in terms of actual scenarios and only find the best points for code optimization, not the use of design patterns. Just like the design mode is suitable for you at the beginning, because there is no real scene simulation case, but some drawing circles and squares, which is very unfriendly to the new person or the partner whose understanding ability is not yet. So even after learning for a long time, but the actual use is still confused.

Second, development environment

  1. JDK 1.8
  2. Idea + Maven
  3. Involving engineering three, can be concerned byThe public,:Bugstack wormhole stackReply,Download the source codeGet (Open the get link and find the serial number 18)
engineering describe
itstack-demo-design-7-01 Implement business requirements with a lump of code
itstack-demo-design-7-02 Design patterns are optimized to adapt code to generate contrast for learning

Iii. Introduction of bridge mode

The main role of the bridge pattern is to combine multiple matching uses by separating the abstract from the implementation. To put it bluntly, the core implementation is A class A with A class B interface, passing the implementation of class B through constructors, and that class B is the bridge of the design.

So what are the scenarios for bridging in our normal development

Implementation of various JDBC drivers, desktop and notebook tablets of the same brand type, multi-class interface in business implementation group filtering service, etc. These scenarios are more suitable to implement using the bridge pattern, because in some combinations where cartesian products can occur if each class implements different services, using the bridge pattern can be very simple.

4. Case scenario simulation

With the market competition, wechat and Alipay have emerged in the payment service industry, including some other payment services, but businesses do not want to change user habits. For example, if my stall can only use wechat or Alipay to pay, it will make my customers sad and not sell eggs and cakes.

At this time, the emergence of third-party platforms, the market accounted for more than 90% of the market payment services are concentrated in their own platform, and then provide such a platform for shops, supermarkets, stalls to use, while supporting face, scanning, password in a variety of ways.

In this case, we simulate a third-party platform to undertake various payment capabilities, and use our own face to make it easier for users to pay. So there is a convergence of multiple payments and multiple patterns, and if you implement a different pattern for each payment, even the inherited classes need to be developed a lot. And as more payment services or methods are added, it will explode.

So now you can think about how would this scenario work?

Five, with a lump of code implementation

The product manager said the boss wanted the demand, as soon as possible, KPI you see!

Since you force me that don’t blame me heartless, I have not a class to write endless demand! Anyway, finished writing is done, take the performance will also go every day to force to write requirements, the code is more and more disorderly love the back of the brother 3 seconds.

1. Engineering structure

itstack-demo-design-7-01└ ─ ─ the SRC └ ─ ─ the main └ ─ ─ Java └ ─ ─ org. Itstack. Demo. The design └ ─ ─ PayController. JavaCopy the code
  • There’s only one class that has them allifelseThis class implements all the functionality of payments and patterns.

2. Code implementation

public class PayController {

    private Logger logger = LoggerFactory.getLogger(PayController.class);

    public boolean doPay(String uId, String tradeId, BigDecimal amount, int channelType, int modeType) {
        // Wechat Pay
        if (1 == channelType) {
            logger.info("Simulated wechat channel payment transfer begins. UId: {} tradeId: {} amount: {}", uId, tradeId, amount);
            if (1 == modeType) {
                logger.info("Password payment, risk control, environmental security.");
            } else if (2 == modeType) {
                logger.info("Face payment, risk control check face recognition.");
            } else if (3 == modeType) {
                logger.info("Fingerprint payment, risk control check fingerprint information."); }}// Pay by Alipay
        else if (2 == channelType) {
            logger.info("Simulation of alipay channel payment accounts began. UId: {} tradeId: {} amount: {}", uId, tradeId, amount);
            if (1 == modeType) {
                logger.info("Password payment, risk control, environmental security.");
            } else if (2 == modeType) {
                logger.info("Face payment, risk control check face recognition.");
            } else if (3 == modeType) {
                logger.info("Fingerprint payment, risk control check fingerprint information."); }}return true; }}Copy the code
  • The above class provides a payment service function by providing the necessary fields;The user ID,Transaction ID,The amount of,channel,modelTo control payment methods.
  • The aboveifelseProbably the worst way to write it, even if YOU write itifelseIt can be written in an optimized way.

3. Test and verify

3.1 Writing test classes

@Test
public void test_pay(a) {
    PayController pay = new PayController();
    System.out.println("\r\n Simulation test scenario; Wechat pay, face mode.");
    pay.doPay("weixin_1092033111"."100000109893".new BigDecimal(100), 1.2);
    
    System.out.println("\r\n Simulation test scenario; Alipay payment, fingerprint method.");
    pay.doPay("jlu19dlxo111"."100000109894".new BigDecimal(100), 2.3);
}
Copy the code
  • The above tests two different payment types and payment modes respectively. Wechat face payment, Alipay fingerprint payment

3.2 Test Results

Simulation test scenario; Wechat payment, face mode.23:05:59.152[the main] INFO O.I.D emo. Design. Pay. Channel. The pay - pay the deposit to start simulation WeChat channels. UId: weixin_1092033111 tradeId:100000109893Amount:100
23:05:59.155[the main] INFO O.I.D emo. Design. Pay. Mode. PayCypher - face pay, risk control check face recognition23:05:59.155[the main] INFO O.I.D emo. Design. Pay. Channel. The pay - simulation WeChat channel payment risk control check. UId: weixin_1092033111 tradeId:100000109893Security:true
23:05:59.155[the main] INFO O.I.D emo. Design. Pay. Channel. The pay pay deposit success - analog WeChat channels. UId: weixin_1092033111 tradeId:100000109893Amount:100Simulation test scenario; Alipay payment, fingerprint mode.23:05:59.156[the main] INFO O.I.D emo. Design. Pay. Channel. The pay - analog channels of alipay to pay deposit. UId: jlu19dlxo111 tradeId:100000109894Amount:100
23:05:59.156[the main] INFO O.I.D emo. Design. Pay. Mode. PayCypher - fingerprint payment, risk control check fingerprint information23:05:59.156[the main] INFO O.I.D emo. Design. Pay. Channel. The pay check - analog channels of alipay payment risk control. UId: jlu19dlxo111 tradeId:100000109894Security:true
23:05:59.156[the main] INFO O.I.D emo. Design. Pay. Channel. The pay - analog channels of alipay to pay deposit. UId: jlu19dlxo111 tradeId:100000109894Amount:100

Process finished with exit code 0
Copy the code
  • According to the test results, our combination of different payment types and payment modes has been satisfied, but such code will become very complicated in the future maintenance and expansion.

Bridge mode refactoring code

Then the bridge pattern was used to optimize the code, which was a minor refactoring.

From the ifelse implementation above, this is a combination of two different types. So you can separate the payment mode from the payment mode and bridge it by using the abstract class to rely on the implementation class, so that the payment mode and the payment mode can actually be used separately, and when you need to combine, you just pass the mode to the payment.

The key to bridge mode is the choice of bridge split, whether such a similar combination can be found, if not, there is no need to use bridge mode.

1. Engineering structure

itstack-demo-design-7-02└ ─ ─ the SRC ├ ─ ─ the main │ └ ─ ─ Java │ └ ─ ─ org. Itstack. Demo. Design. The pay │ ├ ─ ─ channel │ │ ├ ─ ─ pay. Java │ │ ├ ─ ─ WxPay. Java │ │ └ ─ ─ ZfbPay. Java │ └ ─ ─ mode │ ├ ─ ─ IPayMode. Java │ ├ ─ ─ PayCypher. Java │ ├ ─ ─ PayFaceMode. Java │ └ ─ ─ PayFingerprintMode. Java └ ─ ─ Test └ ─ ─ Java └ ─ ─ org. Itstack. The demo, the design, test └ ─ ─ ApiTest. JavaCopy the code

Bridge mode model structure

  • On the left side of thePayIs an abstract class, followed by its two payment type implementations; Wechat Pay, Alipay pay.
  • On the right sideIPayModeIs an interface, and down there are its two payment models; Face payment, fingerprint payment.
  • So,Payment type × The payment modelLambda is equal to the corresponding combination.
  • Note that the face and fingerprint verification logic is also different for each payment method, which can be handled using the adapter mode. This is not the focus of this article, but refer to the adapter mode section.

2. Code implementation

2.1 Payment types bridge abstract classes

public abstract class Pay {

    protected Logger logger = LoggerFactory.getLogger(Pay.class);

    protected IPayMode payMode;

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

    public abstract String transfer(String uId, String tradeId, BigDecimal amount);

}
Copy the code
  • This class defines the account transfer interface for the payment method to be implemented:transferAnd the bridge interface;IPayModeAnd in the constructor, the user chooses the payment method.
  • If you haven’t been exposed to such implementations, focus on themIPayMode payModeThis part is the core of the bridge.

2.2 Realization of two payment types

WeChat pay

public class WxPay extends Pay {

    public WxPay(IPayMode payMode) {
        super(payMode);
    }

    public String transfer(String uId, String tradeId, BigDecimal amount) {
        logger.info("Simulated wechat channel payment transfer begins. UId: {} tradeId: {} amount: {}", uId, tradeId, amount);
        boolean security = payMode.security(uId);
        logger.info("Simulated wechat channel payment risk control verification. UId: {} tradeId: {} Security: {}", uId, tradeId, security);
        if(! security) { logger.info("Simulated wechat channel payment transfer interception. UId: {} tradeId: {} amount: {}", uId, tradeId, amount);
            return "0001";
        }
        logger.info("Simulated wechat channel payment transfer success. UId: {} tradeId: {} amount: {}", uId, tradeId, amount);
        return "0000"; }}Copy the code

Alipay Payment

public class ZfbPay extends Pay {

    public ZfbPay(IPayMode payMode) {
        super(payMode);
    }

    public String transfer(String uId, String tradeId, BigDecimal amount) {
        logger.info("Simulation of alipay channel payment accounts began. UId: {} tradeId: {} amount: {}", uId, tradeId, amount);
        boolean security = payMode.security(uId);
        logger.info("Simulated Alipay channel payment risk control verification. UId: {} tradeId: {} Security: {}", uId, tradeId, security);
        if(! security) { logger.info("Simulated Alipay channel payment transfer interception. UId: {} tradeId: {} amount: {}", uId, tradeId, amount);
            return "0001";
        }
        logger.info("Simulated Alipay channel payment transfer success. UId: {} tradeId: {} amount: {}", uId, tradeId, amount);
        return "0000"; }}Copy the code
  • Here, two payment channels of the third party are simulated respectively. Wechat and Alipay, of course, as comprehensive payment platforms, may not only receive these two channels, but also have many channels.
  • In addition, it can be seen that the interface of risk control is called respectively for verification during payment, that is, payment of different modes (face scan,The fingerprint), all need to go through the specified risk control to ensure payment security.

2.3 Defining the payment mode interface

public interface IPayMode {

    boolean security(String uId);

}
Copy the code
  • Any payment model; Face brushing, fingerprints, and passwords are all subject to varying degrees of security risk control. A security verification interface is defined here.

2.4 Risk control of the three payment modes (face brushing, fingerprint and password)

face scan

public class PayFaceMode implements IPayMode{

    protected Logger logger = LoggerFactory.getLogger(PayCypher.class);

    public boolean security(String uId) {
        logger.info("Face payment, risk control check face recognition.");
        return true; }}Copy the code

The fingerprint

public class PayFingerprintMode implements IPayMode{

    protected Logger logger = LoggerFactory.getLogger(PayCypher.class);

    public boolean security(String uId) {
        logger.info("Fingerprint payment, risk control check fingerprint information.");
        return true; }}Copy the code

password

public class PayCypher implements IPayMode{

    protected Logger logger = LoggerFactory.getLogger(PayCypher.class);

    public boolean security(String uId) {
        logger.info("Password payment, risk control, environmental security.");
        return true; }}Copy the code
  • Here, the risk control verification of three payment modes (face brushing, fingerprint and password) is realized. When users choose different payment types, corresponding risk control interception will be carried out to ensure payment security.

3. Test and verify

3.1 Writing test classes

@Test
public void test_pay(a) {
    System.out.println("\r\n Simulation test scenario; Wechat pay, face mode.");
    Pay wxPay = new WxPay(new PayFaceMode());
    wxPay.transfer("weixin_1092033111"."100000109893".new BigDecimal(100));

    System.out.println("\r\n Simulation test scenario; Alipay payment, fingerprint method.");
    Pay zfbPay = new ZfbPay(new PayFingerprintMode());
    zfbPay.transfer("jlu19dlxo111"."100000109894".new BigDecimal(100));
}
Copy the code
  • Compared to the ifelse implementation above, the invocation here is clean, clean, and easy to use;new WxPay(new PayFaceMode()),new ZfbPay(new PayFingerprintMode())
  • External users of the interface do not need to care about the implementation, just choose to use it as needed.
  • At present, the above optimization is mainly aimed atThe bridge modelTo refactor the if logic part, the call part can be usedThe abstract factoryorThe strategy patternCooperate withmapStructure to configure services. Because the bridge mode is the focus here, there is no need to add extra code to avoid distracting the focus.

3.2 Test Results

Simulation test scenario; Wechat payment, face mode.23:14:40.911[the main] INFO O.I.D emo. Design. Pay. Channel. The pay - pay the deposit to start simulation WeChat channels. UId: weixin_1092033111 tradeId:100000109893Amount:100
23:14:40.914[the main] INFO O.I.D emo. Design. Pay. Mode. PayCypher - face pay, risk control check face recognition23:14:40.914[the main] INFO O.I.D emo. Design. Pay. Channel. The pay - simulation WeChat channel payment risk control check. UId: weixin_1092033111 tradeId:100000109893Security:true
23:14:40.915[the main] INFO O.I.D emo. Design. Pay. Channel. The pay pay deposit success - analog WeChat channels. UId: weixin_1092033111 tradeId:100000109893Amount:100Simulation test scenario; Alipay payment, fingerprint mode.23:14:40.915[the main] INFO O.I.D emo. Design. Pay. Channel. The pay - analog channels of alipay to pay deposit. UId: jlu19dlxo111 tradeId:100000109894Amount:100
23:14:40.915[the main] INFO O.I.D emo. Design. Pay. Mode. PayCypher - fingerprint payment, risk control check fingerprint information23:14:40.915[the main] INFO O.I.D emo. Design. Pay. Channel. The pay check - analog channels of alipay payment risk control. UId: jlu19dlxo111 tradeId:100000109894Security:true
23:14:40.915[the main] INFO O.I.D emo. Design. Pay. Channel. The pay - analog channels of alipay to pay deposit. UId: jlu19dlxo111 tradeId:100000109894Amount:100

Process finished with exit code 0
Copy the code
  • From the test results, the content is the same, but the overall implementation has changed a lot. So sometimes you can’t just look at the results, you have to look at the process

Seven,

  • By simulating two payment channels, wechat and Alipay, under different payment modes,face scan,The fingerprint,password, thus reflects the reasonable application of bridge mode in this kind of scene. It simplifies the code development and increases the expansibility for subsequent iterations of requirements.
  • The bridge pattern implementation meets the single responsibility and open/close principle, making each part of the content clear and easy to maintain and expand, but if we were implementing highly cohesive code, it would be complicated. So when choosing to refactor code, you need to consider the overall design, otherwise you can’t choose a reasonable design pattern, will make the code difficult to develop.
  • The choice and use of any design pattern should be consistent with the scene, do not deliberately use. In addition, because of the complexity of the business, the unified scenario may need to use a combination of multiple design patterns to design the code more reasonably. But this kind of experience needs to be learned from actual projects and applied over time.

Recommended reading

  • 1. Relearn Java design mode: Actual factory method mode (multiple types of commodity award scenario)
  • 2. Relearn Java design pattern: Actual Abstract Factory Pattern (replace Redis dual cluster upgrade scenario)
  • 3. Relearn Java design mode: Actual Constructor mode (decoration material combination package selection scenario)
  • 4. Relearn Java design mode: actual combat prototype mode (multiple sets of tests with each question and answer out of order)
  • 5. Relearn Java design patterns: Effective Java singleton