开发者

Adding handlers for some field values and other extension points

I am building an application where the datamodel is fixed, but people (or just me) can extend it by adding classes that inherit from the base class that gets instantiated from the info in the db and serialized in services.

I have three problem areas with this (case 1 2 and 3 in the sample code below). Case #1 I could maybe solve with an interface, but that doesn't help me with case 2 or 3.

I think the code sample will speak better than my attempts to explain; any idead on how to approach this so that each new field type doesn't need to get manually added to a bunch of places in the code?

    public class ManagerClass
{
    public ManagerClass()
    {

        public ManagerClass()
        {
        }

        //Case #1
        public void process(AllFields allFields)
        {
            foreach (Field field in allFields.Fields)
            {
                //Currently I need to add all extention types as seperate cases here manually
                //...this type 开发者_如何学JAVAof logic appears in several places in the code
                if (field.GetType().Name == "ExtendedField")
                {
                    //Have the extended field do something in a way particular to it
                }
                else
                {
                    //Have the base field do something the "normal" way
                }
            }
        }
        //Case #2
        //Here is another case where currently I am adding each case in by hand
        //fieldType is a string here because I am storing what type of field it is in the DB
        public void create(string value, string fieldType)
        {
            //Currently I need to add all extention types as seperate cases here manually
            if (fieldType == "ExtendedField")
            {
                //Create a ExtendedField
            }
            else
            {
                //Create a Field
            }
        }
    }
}

[DataContract]
//Case #3
[KnownType(typeof(ExtendedField))] //Currently I need to add all extention types here manually
public class AllFields
{
    private List<Field> fields;
    public AllFields(){}

    [DataMember]
    public List<Field> Fields
    {
        get { return fields; }
        set { fields = value; }
    }
}

[DataContract]
public class Field
{
    private string fieldValue;
    public Field(){}

    [DataMember]
    public string FieldValue
    {
        get { return fieldValue; }
        set { fieldValue = value; }
    }
}

[DataContract]
public class ExtendedField : Field
{
    private string someOtherAttribute;
    public ExtendedField(){}

    [DataMember]
    public string SomeOtherAttribute
    {
        get { return someOtherAttribute; }
        set { someOtherAttribute = value; }
    }
}


Sounds like you're trying to build an miniature extensibility framework. Consider something like this where the extension logic is handled by a FieldHandler:

public class FieldHandler
{
   public virtual Field CreateField(string value, string fieldType){...}
}

// Case 2
Field field = null;
foreach (FieldHandler handler in m_handlers)
{
   if (handler.SupportsFieldType(fieldType))
   {
       field = handler.CreateField (value, fieldType);
       continue;
   }
}
if (field == null)
{
   // Create standard field.
   field = ...;
}


For extensible Field reading:

Make Field an abstract class, and make all your common methods abstract as well. Classes derived from Field will specify exactly what those methods do.

You can then pass objects of these derived classes back to methods that accept a Field, and they can call the methods of Field without needing to worry about the real class that is being used. Interface would be even better, but you don't get code reuse for common functionality.

For extensible Field creating:

You will always have to do a switch or something somewhere at the boundaries of your program to determine which class to create. Your goal is to do this in only one place. Your design - determining the factory method to use based on data in the DB - is ideal.

Look into making a class that will have the responsibility to create Field objects based on DB data and just pass it around. If it were abstract, you could subclass it and pass it as a parameter to methods, methods that will get the data they want by calling something like fieldFactory.GetNewField(myParameter);.

For extensible serialization:

Research DataContractResolver.

Tips:

If you find yourself having to switch on the type of Field in more than one place (where the constructors are called), you're doing it wrong. An example of this is your process(field) method. Instead, Field or IField should have an abstract Process method. Consumers will just call Field.Process and not care how it is implemented.

Example:

public abstract class Field
{
   public abstract void Process();
}

public class ExtendedField : Field
{
   public override void Process() { /*Extended Field Specific Stuff Here*/ }
}

//consumer code

public void DoStuffWithABunchOfFieldsOfUnknownType(IEnumerable<Field> fields)
{
   foreach (Field field in fields) { field.Process(); }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜