The Template Method Pattern and the Bridge Design Pattern in modern C++

Is developing software only good (or excellent) knowledge of a programming language? Of course not. There are many things, but one of the most important is to know patterns. It might be not obvious when you develop elementary apps at the beginning of your journey, but it becomes necessary when developing decent packages for professional work. Many books can help you understand the different patterns, irrelevant of the programming language (google it). One very friendly resource that I found recently is the video tutorials by Arjan Egges called ArjanCodes. He shares very nice tutorials based on python. One very nice exercise that you can do is apply the patterns in your projects or…apply the patterns using different languages. The latter is the one that I tried to do. I used C++ to rewrite Arjan’s example and see if it worked. Therefore my suggestion is to watch Arjan’s video first and then read the post to check the C++ version of the story.

The example is based on the development of a trading bot. The bot connects to a crypto exchange and gets the market data. At this point comes the bridge pattern that will help connect with different exchange markets without altering the bot. Then it checks the prices and advice if we need to buy or sell. The advice can be based on different algorithms like average or min-max. Again, the template pattern comes, which helps us to different trading strategies without changing the trading bot. Is it exciting?

The template pattern is suitable for a standard procedure, but the procedure steps can be different depending on the situation. In our case, the procedure is to decide to buy or selling crypto, but the trading strategies could be different. How are we going to implement that? The basic idea is to implement the trading bot as an abstract class, create subclasses, and implement the particular strategies that we like to apply. How it looks like then?

#ifndef TEMPLATEPATTERN__TRADINGBOT_H_
#define TEMPLATEPATTERN__TRADINGBOT_H_
#include <vector>
#include <string>
#include <iostream>
#include "Exchange.h"

class TradingBot {
 public:
  explicit TradingBot(Exchange& exchange) : exchange_{exchange} {}
  void CheckPrices(const std::string& coin);

 protected:
  [[nodiscard]] virtual bool ShouldBuy(const std::vector<int>& prices) const = 0;
  [[nodiscard]] virtual bool ShouldSell(const std::vector<int>& prices) const = 0;
  Exchange& exchange_;
};

#endif//TEMPLATEPATTERN__TRADINGBOT_H_

Yes, we can see, ShouldBuy and ShouldSell are abstract class methods and the CheckPrices that gives us the advice use these abstract methods, like that:

#include "TradingBot.h"

void TradingBot::CheckPrices(const std::string& coin) {
  exchange_.Connect();
  std::vector<int> prices = exchange_.GetMarketData(coin);

  if (this->ShouldBuy(prices)) {
    std::cout << "You should buy " << coin << std::endl;
  } else if (this->ShouldSell(prices)) {
    std::cout << "You should sell " << coin << std::endl;
  } else {
    std::cout << "No action needed for " << coin << std::endl;
  }
}

Good, it starts to make sense. Let’s see now how a subclass looks like:

#ifndef TEMPLATEPATTERN__MINMAXTRADER_H_
#define TEMPLATEPATTERN__MINMAXTRADER_H_
#include "TradingBot.h"
#include <algorithm>

class MinMaxTrader : public TradingBot {
 public:
  explicit MinMaxTrader(Exchange& exchange) : TradingBot(exchange) {}

 protected:
  [[nodiscard]] bool ShouldBuy(const std::vector<int> &prices) const override {
    return (prices.back() == *std::min_element(std::begin(prices), std::end(prices)));
  }
  [[nodiscard]] bool ShouldSell(const std::vector<int> &prices) const override {
    return (prices.back() == *std::max_element(std::begin(prices), std::end(prices)));
  }
};

#endif//TEMPLATEPATTERN__MINMAXTRADER_H_

Well, no surprise, as we expected, the subclass implements the abstract methods, and from now on, we use the subclass to create a trading bot. If we want a different trading strategy, we subclass the trading bot class again and develop the approach we want.

The bridge pattern, obviously, bridges different classes. In our case, the exchange part and the trading bot are two separate things that can vary. We can have different crypto exchange markets, e.g. Coinbase and Binance, and different trading bots, e.g. average and min-max. So, this pattern will allow us to use whatever exchange market we want without changing the trading bot.

How does it start? As usual, I would say by creating an abstract class for exchange.

#ifndef TEMPLATEPATTERN__EXCHANGE_H_
#define TEMPLATEPATTERN__EXCHANGE_H_
#include <vector>
#include <string>

class Exchange {
 public:
  virtual void Connect() = 0;
  virtual std::vector<int> GetMarketData(const std::string& coin) = 0;
};

#endif//TEMPLATEPATTERN__EXCHANGE_H_

Then we can create different subclasses to support different exchange markets like Binance:

#ifndef TEMPLATEPATTERN__BINANCE_H_
#define TEMPLATEPATTERN__BINANCE_H_
#include "Exchange.h"
#include <vector>
#include <string>
#include <iostream>

class Binance : public Exchange {
 public:
  void Connect() override {
    std::cout << "Connecting to Binance exchange..." << std::endl;
  }
  std::vector<int> GetMarketData(const std::string& coin) override {
    return {10, 11, 12, 13};
  }

};

#endif//TEMPLATEPATTERN__BINANCE_H_

How do that bridge with our trading bot? Well, you have seen it already. We define a reference to the abstract Exchange class, and we initialise it in the constructor. Easy, uhhh?

I know that my explanation is minimal, but the idea is first to watch Arjan’s video tutorial in this link and then see the C++ implementation as the cherry on the top. I hope that makes sense.

The repository that contains the code can be found in GitHub here.

Enjoy!