Blog author:
Niladri.Biswas | Posted on: 5/1/2012 | Category:
Pattern and Practices Blogs | Views: 665 | Status:
[Member] |
Points: 75
|
Alert Moderator
Download source file
Introduction
Sometimes we come across situations where the problem comes under 2^n problem category type. for example, say we have a checkbox. Now it has barely two states viz.ON/OFF
(I am ignoring the tri-state condition). So for a single checkbox, the value is 2^1 = 2. Likely, for two checkbox, the total combination that will appear will be 2^2 = 4.
For three checkbox, it will be 2^3 = 8. And so on.
Now writing a program for these kind of situation is really tedious as describe under(pseudo code)
Case 1: For input = 1
IF CHECKBOX1.CHECK = TRUE THEN 1
ELSE 0
Case 2: For input = 2
IF CHECKBOX1.CHECK = TRUE THEN 1
ELSE 0
IF CHECKBOX2.CHECK = TRUE THEN 1
ELSE 0
IF CHECKBOX1.CHECK = TRUE AND CHECKBOX2.CHECK = TRUE THEN 1
ELSE 0
IF CHECKBOX1.CHECK = FALSE AND CHECKBOX2.CHECK = FALSE THEN 1
ELSE 0
...and so on. Now try the same for input = 3,4,5,etc. and we will come to know the dificulty of writing such a program and maintainability of the same.
To ease this kind of situation, the Replacement Design Pattern has come into picture
How it works?
In the case of Replacement DP, it initially constructs the entire string and then depending on the value (ON/OFF), it replaces the string.
e.g. with 3 inputs
Step 1: Intial string
string initialString = Checkbox1.Value + Checkbox2.Value + Checkbox3.value
Step 2: Replace the string based on the value supplied(ON/OFF)
Suppose for Checkbox1, value is ON
For Checkbox2, value is OFF
For Checkbox3, value is ON
//Build Checkbox1 option
initialString = Checkbox1.Check
? ReplaceAll(initialString, Checkbox1.Value, Checkbox1.Value)
: ReplaceAll(initialString, Checkbox1.Value , string.Empty);
//Build Checkbox2 option
initialString = Checkbox2.Check
? ReplaceAll(initialString, Checkbox2.Value, Checkbox2.Value)
: ReplaceAll(initialString, Checkbox2.Value , string.Empty);
//Build Checkbox1 option
initialString = Checkbox3.Check
? ReplaceAll(initialString, Checkbox3.Value, Checkbox3.Value)
: ReplaceAll(initialString, Checkbox3.Value , string.Empty);
The helper function "ReplaceAll" will just do a simple replacement
private static string ReplaceAll(string expression, string oldValue, string newValue)
{
return expression.Replace(oldValue, newValue);
}
So the final output will be
Checkbox1.Value + Checkbox3.value
A concrete example
Consider the below input
What we have to do is that, depending on the country chosen, the output needs to be displayed
So let us first construct a constant class as under
public class Constants
{
public const string INDIA = "India";
public const string USA = "USA";
public const string SWEDEN = "Sweden";
public const string SPAIN = "Spain";
public const string SRILANKA = "Srilanka";
public const string BURMA = "Burma";
public const string CHINA = "China";
public const string NORWAY = "Norway";
public const string TRUE = "=True";
}
Next, let us make a country entity
public class CountryEntity
{
public bool IsIndia { get; set; }
public bool IsUSA { get; set; }
public bool IsSweden { get; set; }
public bool IsSpain { get; set; }
public bool IsSrilanka { get; set; }
public bool IsBurma { get; set; }
public bool IsChina { get; set; }
public bool IsNorway { get; set; }
}
Next let us make the interface "IReplacementDP" which will have "Replace" method expose
public interface IReplacementDP
{
string Replace(object obj);
}
The concrete class that will implement the "IReplacementDP" will be as under
public class ReplacementDP : IReplacementDP
{
public string Replace(object obj)
{
var objCountryEntity = obj as CountryEntity;
//Create the Display Option Structure
string DisplayOptionStructure =
Constants.INDIA + ";" +
Constants.USA + ";" +
Constants.SWEDEN + ";" +
Constants.SPAIN + ";" +
Constants.SRILANKA + ";" +
Constants.BURMA + ";" +
Constants.CHINA + ";" +
Constants.NORWAY + ";";
//Build India option
DisplayOptionStructure = objCountryEntity.IsIndia
? ReplaceAll(DisplayOptionStructure, Constants.INDIA, Constants.INDIA + Constants.TRUE)
: ReplaceAll(DisplayOptionStructure, Constants.INDIA + ";", string.Empty);
//Build USA option
DisplayOptionStructure = objCountryEntity.IsUSA
? ReplaceAll(DisplayOptionStructure, Constants.USA, Constants.USA + Constants.TRUE)
: ReplaceAll(DisplayOptionStructure, Constants.USA + ";", string.Empty);
//Build Sweden option
DisplayOptionStructure = objCountryEntity.IsSweden
? ReplaceAll(DisplayOptionStructure, Constants.SWEDEN, Constants.SWEDEN + Constants.TRUE)
: ReplaceAll(DisplayOptionStructure, Constants.SWEDEN + ";", string.Empty);
//Build Spain option
DisplayOptionStructure = objCountryEntity.IsSpain
? ReplaceAll(DisplayOptionStructure, Constants.SPAIN, Constants.SPAIN + Constants.TRUE)
: ReplaceAll(DisplayOptionStructure, Constants.SPAIN + ";", string.Empty);
//Build Srilanka option
DisplayOptionStructure = objCountryEntity.IsSrilanka
? ReplaceAll(DisplayOptionStructure, Constants.SRILANKA, Constants.SRILANKA + Constants.TRUE)
: ReplaceAll(DisplayOptionStructure, Constants.SRILANKA + ";", string.Empty);
//Build Burma option
DisplayOptionStructure = objCountryEntity.IsBurma
? ReplaceAll(DisplayOptionStructure, Constants.BURMA, Constants.BURMA + Constants.TRUE)
: ReplaceAll(DisplayOptionStructure, Constants.BURMA + ";", string.Empty);
//Build China option
DisplayOptionStructure = objCountryEntity.IsChina
? ReplaceAll(DisplayOptionStructure, Constants.CHINA, Constants.CHINA + Constants.TRUE)
: ReplaceAll(DisplayOptionStructure, Constants.CHINA + ";", string.Empty);
//Build Norway option
DisplayOptionStructure = objCountryEntity.IsNorway
? ReplaceAll(DisplayOptionStructure, Constants.NORWAY, Constants.NORWAY + Constants.TRUE)
: ReplaceAll(DisplayOptionStructure, Constants.NORWAY + ";", string.Empty);
return FormatExpression(DisplayOptionStructure, ";");
}
#region Helper Methods
private string ReplaceAll(string expression, string oldValue, string newValue)
{
return expression.Replace(oldValue, newValue);
}
private string FormatExpression(string expression, string delimeter)
{
return
expression.Length > 0
? expression.Substring(0, expression.Length-1)
: expression;
}
#endregion
}
Finally, the client that will invoke will be as under
private void button1_Click(object sender, RoutedEventArgs e)
{
IReplacementDP ireplacementDP = new ReplacementDP();
Func result = x => ireplacementDP.Replace(x);
MessageBox.Show(result(SetRequest()));
}
private CountryEntity SetRequest()
{
return new CountryEntity
{
IsIndia = chkIndia.IsChecked.Value
, IsBurma = chkBurma .IsChecked.Value
, IsChina = chkChina.IsChecked.Value
, IsNorway =chkNorway.IsChecked.Value
, IsSrilanka =chkSrilanka.IsChecked.Value
, IsSpain = chkSpain.IsChecked.Value
, IsSweden =chkSweden.IsChecked.Value
, IsUSA =chkUSA.IsChecked.Value
};
}
The class diagram is as under
Conclusion
The term has been coined by myself and this pattern got evolved as a part of my project. So I thought of sharing the same here.I hope while dealing with 2^n problem, this DP will help us in developing the code as well as maintenance.
Hope the article will be useful.Source code is attached herewith.
Best Regards,
Niladri Biswas