Good day,
I'm writing a program 'geocalculator' as an assignment at our university. I faced up with a design problem. An interface contains two groups: A and B. Each group consists of two comboboxes and a table. The first combobox allows user to choose between a couple of reference systems (WGS-84, SK-42, SK-95, etc.). The second - between geodetic, spatial and planimetric coordinate systems. The table is used to input a bunch of points (label, X (or B), Y (or L), Z (or H)). Conversion functions involve a lot of constants and massive formulas.
My question is: what is the best way to organize code, connect comboboxes and functions in order to call appropriate conversion function?
Let's come to the point. I subclassed an abstract model (PointsModel) where all my points are being stored. It has no idea about comboboxes and algorithms. The comboboxes are declared inside of a MainWindow class. My model do have custom delegate: it is used to convert representation of the input coordinates from sexadecimal (degrees, minutes and seconds) to decimal (decimal degrees). I have two buttons (actions on the toolBar): convert points from A to B and vice versa. I imagine the process in the next way:
I don't want to do it via "if else" statements! Because there would be a huge number of condition statements (if the one combobox is WGS-84 and the other is SK-42 then do this, if the one combobox is SK-42 and the other is WGS-84 then do this and so on and so forth for a bunch of reference systems).
I have some ideas about declaring functions and corresponding functors. I would like to attach this functors to the comboboxes in some way and then the time comes just call a general method, which would automatically redirect the call to the required function.
I'll describe two popular choices: Look up table and event handler (a.k.a. button press). The selection of the algorithm depends on your calculator implementation.
The fundamentals here is that you want to associate a function with a symbol. For example, your parser wants to evaluate the '+' for the expressions on the stack. Rather than using a switch
or an if-elseif
ladder, you could look up a function that is associated with '+' and execute the function with the two expressions.
// Synonym for a pointer that accepts two parameters,
// performs an operation, and returns the result as a string.
typedef std::string (*Function_Pointer(const std::string& param1, const std::string& param2))
struct Table_Entry
{
const char * operator_text;
Function_Pointer p_operaton_function;
};
const Table_Entry Operation_Table[] =
{
{"+", Perform_Addition},
{"-", Perform_Subtraction},
{"*", Perform_Multiplication},
};
// Or
typedef std::map<std::string, Function_Pointer> Operation_Container;
//...
Operation_Container operations_map;
operations_map["+"] = Perform_Addition;
operations_map["-"] = Perform_Subtraction;
Another idea is to put the computation inside the handler for the button.
void On_Button_Dash(Event& e)
{
result = operand_1 - operand2;
}
Another alternative is to create a base class for the operations. The base class would have an abstract method to evaluate or perform the operation. Define child classes for each operation. Create the operation classes during lexing phase and store in a vector of pointers to base classes.
You main loop could be:
std::vector<Base_Operation *> operations;
for (unsigned int i = 0; i < operations.size(); ++i)
{
operations[i].Evaluate(parameter_1, parameter_2);
}