views:

94

answers:

6

Lets say I want to make few classes to determine behaviour of agents.
The good practice would be to make some common interface for them, such interface (simplified) could look like this:

interface IModel
{
     void UpdateBehaviour();
}

All , or at least most, of such model would have some parameters, but parameters from one model might have nothing in common with parameters of other model.
I would like to have some common way of loading parameters.

Question

What is the best way to do that?
Is it maybe just adding method void LoadParameters(object parameters) to the IModel?
Or creating empty interface IParameters and add method void LoadParameters(IParameters parameters)?
That are two ideas I came up with, but I don't like either of them.

+2  A: 
  • you can have your parameters in a Map, but this is not compile-time safe.
  • you can have a setParameters(..) method which takes IParameters (which doesn't define methods), and use downcasting in each specific implementation

An example for the 2nd option is (Java) CertPathValidator, which takes CertPathParameters as an input, which does not define any methods (apart from clone())

Bozho
@Bozho: But isn't it a little bit weird that IParameters is empty interface? I mean is it common practice to make empty interface?
Tomek Tarczynski
not rare at least. In standard Java APIs for example there are a number of examples.
Bozho
.NET has a few instances of "marker" interfaces, but they're discouraged. See e.g. http://msdn.microsoft.com/en-us/library/ms229022%28v=VS.90%29.aspx
Kyralessa
downcasting is a bad code smell
David
+3  A: 

It only makes sense to use a common interface when you are going to use common code to work against that interface.

In this situation, by definition, there is something in common between the classes.

Remember, interfaces are a contract, but they (conceptually) provide a different contract than inheritance. Instead of forming an object hierarchy, and defining that an object is some concrete form of another object, with interfaces, you're providing a contract that says that the object is usable in a specific way, or acts in specific manner.

In your case, an IParameterBag or similar interface may make sense. Compare this to ISerializable in the base class library. There, you have an interface that can be implemented by anything -but always treated in a single manner.

Reed Copsey
+1  A: 

I met a similar problem some time ago and I was choosing between 2 solutions (code in java):

public abstract class Model {
   public Model (Map<String, String> initParams) { }
}

and

public abstract class Model {
   public Model (InitParams params) { }
}

where InitParams is a marker interface which has different implementations one per concrete Model subclass.

Roman
A: 

If the parameters have nothing in common, then they probably shouldn't be referenced by an interface. Here is one way you can work around this:

AgentA agentA = new AgentA();
agentA.setFooParameter("someValue");
someMethod(agentA);

AgentB agentB = new AgentB();
agentB.setBarParameter(true);
someMethod(agentB);

where someMethod accepts the interface of the agent rather than a concrete class

public void someMethod(IModel genericAgent)
{
  ...
}

Essentially, instantiate the agents (which all extend IModel) as concrete classes (rather than IModel agentA = new AgentA();), set the parameters you need to on the concrete class and then pass around the interface rather than the concrete class.

Chris Knight
@Chris: I think You misunderstood my concept. Agent doesn't implement IModel. CLass that implements IModel takes (in constructor or in some other way) some collection of agents and determines their behaviour by UpdateBehaviour() method.
Tomek Tarczynski
+1  A: 

It sounds like you might want to go the route of using a marker interface and use a Factory to initialize and return an concrete instance of IModel.

David
@David: That's deffinitely some alternative.
Tomek Tarczynski
+1  A: 

1) add LoadParamsXml method to the interface

2) create a base class ModelBase

3) use LINQToXml to parse xml

4) use reflection to assign xml properties to the entity's public fields

public override bool LoadParamsXml(string source)
{


            XDocument doc = XDocument.Parse(source, LoadOptions.PreserveWhitespace);

            var parameters = from u in doc.Descendants("parameterType")
                        select new
                        {
                            id = (int)u.Attribute("id"),
                            name = u.Attribute("name").Value,
                            value = u.Attribute("value").Value,
                            typeId = (int)u.Attribute("typeId"),
                            nullValue = u.Attribute("nullValue").Value
                        };

//...
//..

   foreach (var item in parameters)
   {
      SetProperty<T>(this, item.name, item.value);
   }
   return true;
}


protected virtual void SetProperty<T>(T obj, string propertyName, string value) where T : IModel
        {
            typeof(T).GetProperty(propertyName).SetValue(obj, value, null);
        }
igor