There are cases where an if-class explosion can happens. Specifically, if explosion happens when there are many if statements to implements and class explosion happens when there are many class that requires those if to be implemented. When these two explodes on their own dimension, the product is called if-class explosion. In order to solve this, bridge pattern are being used. But more importantly, in order to understand that if such a pattern is required, commonality-variability analysis of the given problem must be done.
Consider the below problem, where we do commonality-variability analysis to identify the if-class explosion.
Create a library of UI controls (ListBox, Grid, Button). These should be created as C++ classes. Various application are to be developed using these classes. Each UI class will has to render the respective UI on the screen, once application requires it. This drawing should be performed by directX on Windows, openGL on linux, Metal on Mac and some other library on VxWorks. It is important to use these specific libraries on the respective systems, as they use GPU to do the drawings. The ListBox, Grid, Button etc should internally use DirectX, openGL, Metal to perform drawing but based on which OS. But we have no control over which OS we will be on.
In the comment section, the commonality-variablity analysis of the problem has been done. Based on that, we come to know that Bridge pattern has to be used.
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class DrawingLibrary
{
public:
static DrawingLibrary *dl;
DrawingLibrary(/*this*/) {}
virtual void drawRectangle(int x1, int y1, int x2, int y2, int borderColor, int fillColor, vector<int> borderRadius) = 0;
/*void drawEllipse(int x1, int y1, int x2, int y2, int borderColor, int fillColor, int xRadius, int yRadius);
void drawArc(int x1, int y1, int x2, int y2, int borderColor, int fillColor, int xRadius, int yRadius);
void drawPath(int borderColor, int fillColor, vector<int> points);
void drawBezier(int borderColor, int fillColor, vector<int> points);
void drawText(string text, string fontName, int fontSize, int fontColor, int x, int y);
void drawImage(string filename, int x, int y);*/
};
//----------------------Implementation-----------------------------
class DirectXAdapter : public DrawingLibrary
{
void drawRectangle(int x1, int y1, int x2, int y2, int borderColor, int fillColor, vector<int> borderRadius) {
cout << "Rectangle using DirectX" << endl;
}
};
class OpenGLAdapter : public DrawingLibrary {
void drawRectangle(int x1, int y1, int x2, int y2, int borderColor, int fillColor, vector<int> borderRadius) {
cout << "Rectangle using OpenGL" << endl;
}
} oa;
class MetalAdapter : public DrawingLibrary {
void drawRectangle(int x1, int y1, int x2, int y2, int borderColor, int fillColor, vector<int> borderRadius) {
cout << "Rectangle using Metal" << endl;
}
};
//----------------------------------abstraction below--------------------------------
// Base class for UI Control
class UIControl
{
protected:
DrawingLibrary *dl = nullptr; //Pointer for late binding
public:
UIControl() {
dl = DrawingLibrary::dl;
}
virtual void drawUI() = 0;
};
class ListBox : public UIControl
{
public:
void draw() {
dl->drawRectangle(0,0,0,0,0,0, vector<int>());
// TODO: Draw text
}
};
class Grid : public UIControl
{
public:
void draw() {
}
};
class Button : public UIControl
{
public:
void draw() {
// TODO: Draw Circle
// TODO: Draw text
}
};
// --------------- apps for testing ---------------
class App1
{
public:
void show() {
ListBox lb;
lb.draw();
}
};
int main()
{
App1 application;
application.show();
return 0;
}