Tuesday, August 26, 2025

Strategy and Factory Pattern Combo

 Strategy and Factory Patterns 

These two design patterns go quite hand in hand. While strategy is a behavioral pattern, the factory is a creational pattern. 

Strategy Patterns: Allows us to create interchangeable code that can be changed at runtime. Basically we create an interface and multiple concrete classes implementing that interface each concrete class would have a algorithm to be applied . Any of these concrete classes can be used as long as they implement the interface.  

Factory Pattern: Allows us to create patterns without specifying the exact type. In this pattern we return an interface and the actual object. The core behavior of the factory pattern is that it allows creation of an object based on an interface and return the same. This works hand in hand with Strategy as factory can take care of creating the object based on the strategy (logic) that has to be applied.     

Thursday, August 21, 2025

Runtime Controls

 Runtime controls can provide a lot of flexibility and sometimes this is required. I spent a lot of time to understand the details of how this works. Below are the basics 

  • Runtime controls should be created 
In the below code snipped, a group control is being used to add all the controls to. As the same group is being used multiple times the code clears off all the controls at the start and then adds new controls. 

 
	    str                 controlName;
            FormStringControl   formBuildLookupControl, formBuildStringControl;
            FormIntControl      formBuildIntControl;
            FormDateControl     formBuildDateControl;
            FormRealControl     formBuildRealControl;
            FormGroupControl    FormBuildGroupControl;

            //unload all the existing controls within the given group
            while ( GroupVariables.controlCount() )
            {
                element.design().removeControl( GroupVariables.controlNum(1).id() );
            }

            _controlsMap = QtnPackageLineControls::loadControls( _pkgCode, _NewItem.data() );
            _controlsEnumerator = _controlsMap.getEnumerator();

            //add all the controls to the group
            while ( _controlsEnumerator.moveNext() )
            {
                QtnPackageLineParams    _controlParams = _controlsEnumerator.currentValue();
                controlName = _controlsEnumerator.currentKey();
            
                FormBuildGroupControl = GroupVariables.addControl( FormControlType::Group, strFmt("%1Group", controlName));
                FormBuildGroupControl.caption( _controlParams.parmControlLabel() );
                FormBuildGroupControl.visible(true);

                switch (_controlParams.parmControlType() )
                {
                    case QtnPackageConfigTypesEnum::Date:
                        FormBuildDateControl = FormBuildGroupControl.addControl( FormControlType::Date, controlName);
                        FormBuildDateControl.registerOverrideMethod( methodStr( FormDateControl, modified ), methodStr(QtnPackageConfigLookupValue, "DynamicsDateControl_modified"), runTimeMethods);
                        FormBuildDateControl.visible(true);

                        break;

                    case QtnPackageConfigTypesEnum::Integer:
                        formBuildIntControl = FormBuildGroupControl.addControl( FormControlType::Integer, controlName);
                        formBuildIntControl.registerOverrideMethod( methodStr( FormDateControl, modified ), methodStr(QtnPackageConfigLookupValue,"DynamicsIntControl_modified"), runTimeMethods);
                        formBuildIntControl.visible(true);
                        break;

                    case QtnPackageConfigTypesEnum::Lookup:
                        FormBuildStringControl = FormBuildGroupControl.addControl( FormControlType::String, controlName);
                        FormBuildStringControl.registerOverrideMethod(methodStr( FormStringControl, modified ),  methodStr(QtnPackageConfigLookupValue,"DynamicsStringControl_modified"), runTimeMethods);
                        FormBuildStringControl.registerOverrideMethod(methodStr( FormStringControl, lookup ),  methodStr(QtnPackageConfigLookupValue,"DynamicsStringControl_lookup"), runTimeMethods);
                        FormBuildStringControl.lookupOnly(true);
                        FormBuildStringControl.visible(true);
                        break;

                    case QtnPackageConfigTypesEnum::Real:
                        FormBuildRealControl = FormBuildGroupControl.addControl( FormControlType::Real, controlName);
                        FormBuildRealControl.registerOverrideMethod( methodStr( FormDateControl, modified ),methodStr(QtnPackageConfigLookupValue,"DynamicsRealControl_modified"), runTimeMethods);
                        FormBuildRealControl.visible(true);
                        break;

                    case QtnPackageConfigTypesEnum::String:
                        FormBuildStringControl = FormBuildGroupControl.addControl( FormControlType::String, controlName);
                        FormBuildStringControl.registerOverrideMethod(methodStr( FormStringControl, modified ),  methodStr(QtnPackageConfigLookupValue,"DynamicsStringControl_modified"), runTimeMethods);
                        FormBuildStringControl.visible(true);
                        break;
                }
            }

 

  • The registerOverrideMethod should be used to provide a callback method 
When the controls are created the override method is also provided. There are multiple parts to the override methods as shown below: 
   formButtonControl.registerOverrideMethod(
    methodStr(FormButtonControl,clicked), //method to override
    methodStr(testClass,testMethod),      //method to invoke
    new testClass());                     //object of class containing method

 The registerOverideMethod is called using an instance of a control, so it already knows which source object is being overloaded. The rest of the parameters are used as follows: 

  1. The first parameter identifies the method of this object to overload. The name of the method can be identified using the methodStr function; make sure to use the right control type class.  
  2. The second parameter the target method to be called instead 
  3. The third parameters identified the runtime object to find the target methods in

  • The next step is to create the callback method that would be called at runtime on the control being created and loaded 
    public boolean DynamicsIntControl_modified(FormControl _control)
    {
        boolean ret = true;
        
        info("control is modified");
        
        return ret;
    }

Below are some of the points to note about the runtime callback function:

  1.  This method should always have a parameter of type FormControl type.
  2.  The name of the method can be anything. The signature of the method can be determined by checking an actual method of a similar contol on the form.

Like in the above example we can create a modified method on a Integer type of control. Because the modified method of an integer control has a return value of boolean; we use the same return types in the callback method.