Below is working code of a semi complete program. Its purpose is to take an input string of any type and modify it based on rules defined for each type. So in this example I pass it a string in CSV format and modify some of the fields.
My questions are
Can the use of interfaces be improved?
How can I handle different string modification patterns (I currently make it work by using
IStringModificationPattern
- but I want to extend this to other types like HTML)?What design changes/ additions can I make to integrate the string modification pattern into a configuration class (i.e. using an XML file based settings)?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StringModificationTest
{
class Program
{
static void Main(string[] args)
{
//usage example
//
string inputText = "CSV,field1,field2,field3,field4,field5,field6,field7,,,,";
StringModifier SM = new StringModifier();
string outputText = SM.ModifyString(inputText);
}
}
StringModifier class
public class StringModifier
{
private List<IStringType> RegisteredTypes = new List<IStringType>();
private IStringModificationPattern ModificationPattern;
public StringModifier()
{
RegisterTypes();
}
private void RegisterTypes()
{
RegisteredTypes = TypeFactory.GetTypeList();
}
public string ModifyString(string str)
{
///sets the message and sets the Modification pattern
IString detectedStr = DetectStringType(str);
///returns the modified string
return detectedStr.Modify(ModificationPattern);
}
private IString DetectStringType(string str)
{
IString msg = new NullString(str);
for (int i = 0; i < RegisteredTypes.Count; i++)
{
if (str.StartsWith(RegisteredTypes[i].start))
{
//set string type
msg = RegisteredTypes[i].getNewInstance(str);
//set modification pattern
ModificationPattern = RegisteredTypes[i].MODPattern;
}
}
return msg;
}
}
TypeFactory static class
internal static class TypeFactory
{
public static List<IStringType> GetTypeList()
{
List<IStringType> types = new List<IStringType>();
types.AddRange(from assembly in AppDomain.CurrentDomain.GetAssemblies()
from t in assembly.GetTypes()
where t.IsClass && t.GetInterfaces().Contains(typeof(IStringType))
select Activator.CreateInstance(t) as IStringType);
return types;
}
}
IStringType interface
public interface IStringType
{
string start { get; }
IString getNewInstance(string STR);
IStringModificationPattern MODPattern { get; }
}
IStringType Implementations
public class CSVType : IStringType
{
public string start { get { return @"CSV,"; } }
public IStringModificationPattern MODPattern { get { return new CSV_StringModificationPattern(); } }
public IString getNewInstance(string str)
{
return (IString)(new CSVString(str));
}
}
public class HTMLStringType : IStringType
{
public string start { get { return @"<HTML>"; } }
public IStringModificationPattern MODPattern { get { return new HTML_StringModificationPattern(); } }
public IString getNewInstance(string str)
{
return (IString)(new HTMLString(str));
}
}
IString interface
public interface IString
{
string STR { get; }
string Modify(IStringModificationPattern MODPattern);
}
IString implementations
public class CSVString : IString
{
public string STR { get; set; }
public List<string> CSVFields { get; set; }
public CSVString(string str)
{
STR = str;
CSVFields = new List<string>();
CSVFields.AddRange(str.Split(','));
}
public string Modify(IStringModificationPattern MODPattern)
{
string output = STR;
foreach (int i in MODPattern.location)
{
CSVFields[i] = "BLAH";
}
//rebuild string
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int i = 0; i < CSVFields.Count; i++)
{
sb.Append(CSVFields[i]);
if (i != CSVFields.Count - 1)
sb.Append(',');
}
output = sb.ToString();
return output;
}
}
public class HTMLString : IString
{
public string STR { get; set; }
public HTMLString(string str)
{
STR = str;
}
public string Modify(IStringModificationPattern MODPattern)
{
string output = STR;
return output;
}
}
public class NullString : IString
{
public string STR { get; set; }
public NullString(string str)
{
STR = str;
}
public string Modify(IStringModificationPattern MODPattern)
{
string output = STR;
//Do nothing
return output;
}
}
IStringModificationPattern interface
public interface IStringModificationPattern
{
List<int> location { get; set; }
}
IStringModificationPattern implementations
public class CSV_StringModificationPattern : IStringModificationPattern
{
//defines the fields that need to be modified
public List<int> location { get; set; }
public CSV_StringModificationPattern()
{
location = new List<int>();
location.Add(2);
location.Add(5);
}
}
public class HTML_StringModificationPattern : IStringModificationPattern
{
public List<int> location { get; set; }
}
}
EDIT: Revised Code taking into consideration feedback below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StringModificationTest2
{
class Program
{
static void Main(string[] args)
{
//usage example
//
string inputText = "CSV,field1,field2,field3,field4,field5,field6,field7,,,,";
StringModifier SM = new StringModifier();
string outputText = SM.Modify(inputText);
}
}
public class StringModifier
{
private readonly List<IStringModificationPattern> _registeredPatterns;
private readonly StringPatternDetector Detector;
public StringModifier()
{
_registeredPatterns = StringModificationPatternFactory.GetTypeList();
Detector = new StringPatternDetector();
}
public string Modify(string inputValue)
{
//get the modification pattern that belongs to this string, and the string object
IStringModificationPattern Modificationpattern = Detector.DetectPattern(this._registeredPatterns, inputValue);
IString StringObject = Detector.StringObject;
//execute correct modification algorithm on the input string
return StringObject.Modify(Modificationpattern); ;
}
}
public class StringPatternDetector
{
private IStringModificationPattern _pattern;
public IString StringObject { get; private set; }
public StringPatternDetector()
{
StringObject = new DEFAULTString(string.Empty);
}
public IStringModificationPattern DetectPattern(List<IStringModificationPattern> registeredPatterns, string value)
{
for (int i = 0; i < registeredPatterns.Count; i++)
{
if (value.StartsWith(registeredPatterns[i].start))
{
_pattern = registeredPatterns[i];
}
}
if (_pattern != null)
StringObject = _pattern.getNewInstance(value);
else
StringObject = new DEFAULTString(value);
return _pattern;
}
}
internal static class StringModificationPatternFactory
{
public static List<IStringModificationPattern> GetTypeList()
{
List<IStringModificationPattern> types = new List<IStringModificationPattern>();
types.AddRange(from assembly in AppDomain.CurrentDomain.GetAssemblies()
from t in assembly.GetTypes()
where t.IsClass && t.GetInterfaces().Contains(typeof(IStringModificationPattern))
select Activator.CreateInstance(t) as IStringModificationPattern);
return types;
}
}
public interface IString
{
string STR { get; }
string Modify(IStringModificationPattern MODPattern);
}
public class CSVString : IString
{
public string STR { get; set; }
public List<string> CSVFields { get; set; }
public CSVString(string str)
{
STR = str;
CSVFields = new List<string>();
CSVFields.AddRange(str.Split(','));
}
public string Modify(IStringModificationPattern MODPattern)
{
string output = STR;
foreach (int i in MODPattern.location)
{
CSVFields[i] = "BLAH";
}
//rebuild string
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int i = 0; i < CSVFields.Count; i++)
{
sb.Append(CSVFields[i]);
if (i != CSVFields.Count - 1)
sb.Append(',');
}
output = sb.ToString();
return output;
}
}
public class HTMLString : IString
{
public string STR { get; set; }
public HTMLString(string str)
{
STR = str;
}
public string Modify(IStringModificationPattern MODPattern)
{
string output = STR;
return output;
}
}
public class DEFAULTString : IString
{
public string STR { get; set; }
public DEFAULTString(string str)
{
STR = str;
}
public string Modify(IStringModificationPattern MODPattern)
{
string output = STR;
//Do nothing
return output;
}
}
public interface IStringModificationPattern
{
string start { get; set; }
List<int> location { get; set; }
IString getNewInstance(string value);
}
public class CSV_StringModificationPattern : IStringModificationPattern
{
public string start { get { return @"CSV,"; } set { this.start = value; } }
//defines the fields that need to be modified
public List<int> location { get; set; }
public CSV_StringModificationPattern()
{
location = new List<int>();
location.Add(2);
location.Add(5);
}
public IString getNewInstance(string value)
{
return (IString)(new CSVString(value));
}
}
}