views:

103

answers:

3

I have two separate lists of entities:

class EntityCollection : IList<Entity>
{
    //...
}

EntityCollection Foo;
EntityCollection Bar;

I want to implement an operation to move an object Qux that is on list Foo to Bar. What's the best way to implement it?

  • As a MoveTo instance method on EntityCollection:

    public void MoveTo(EntityCollection to, Entity entity);
    
    
    // Client code
    Foo.MoveTo(Bar, Qux);
    
  • As a MoveFrom instance method on EntityCollection:

    public void MoveFrom(EntityCollection from, Entity entity);
    
    
    // Client code
    Bar.MoveFrom(Foo, Qux);
    
  • As a static Move method on EntityCollection:

    public static void Move(Entity entity, EntityCollection from, EntityCollection to);
    
    
    // Client code
    EntityCollection.Move(Qux, Foo, Bar);
    
  • As a Move instance method on the class that holds boths collections:

    public void Move(Entity entity, EntityCollection from, EntityCollection to);
    
    
    // Client code
    Holder.Move(Qux, Foo, Bar);
    

Alternatively, and since the entities can only be in one collection at a time, I could have the entities track their location themselves, and implement it on the entity itself:

    public void MoveTo(EntityCollection to)
    {
       if(Location != null)
           Location.Remove(this);
       to.Add(this);
       Location = to;
    }

    // Client code
    Entity e;
    e.MoveTo(Foo);

    // Later on...
    e.MoveTo(Bar);

When presented with so many options, I want to know: where does the move method belong? And why?

A: 

How about using an extension method?

Client code would be:

Foo.Move(Qux).To(Bar);

The signatures:

public static Entity Move(this EntityCollection from, Entity entity)
public static void To(this Entity entity, EntityCollection to)

Fluent!

Adrian Godong
So you're basically calling remove "move" and add "to". I like the look of it in this situation, but I shudder to think what code that uses either Move() or To() by itself would be like to read.
Sean Nyman
@Darth Eru Yes... :D
Adrian Godong
I don't like this because I'd prefer it to be a single operation. My first thought upon seeing this was exactly the same as Darth Eru's: what if I write Foo.Move(Qux)? It does look nice though.
Martinho Fernandes
Maybe Move could return some partial Command object (see GoF) holding the entity and the source, instead of the Entity. I think that would be better, because only To would actually do something, instead of splitting the operation.
Martinho Fernandes
+1  A: 

MoveTo and MoveFrom are both going to be using a call to Add() and Remove() so you could do both of those in one function. In that case you could do something like this:

enum MoveDirection
{
    ToFoo = 0
    ToBar = 1
}

MoveItem(Entity entity, MoveDirection direction)
{
    if direction = 0
       //move entity from Bar to Foo
    elseif direction = 1
       //move entity from Foo to Bar
    endif
}
Jacob Ewald
And how are you going to use it? Put the client code in.
Adrian Godong
I think he means to put it in the class that contains both collections, like this: `Holder.MoveItem(Foo, ToBar)`.
Martinho Fernandes
`Holder.MoveItem(Foo, MoveDirection.ToBar)`, I mean
Martinho Fernandes
@Martinho, correct. Sorry for leaving out the client code part of my answer. Whatever class is holding the two collections (Foo and Bar) would have the MoveItem definition.
Jacob Ewald
I think I'm going with either that option, or the one of putting it in the entity.
Martinho Fernandes
+1  A: 

Ultimately, I don't think it matters too much, so my soft answer would be to not fret.

Linguistically, MoveTo seems more natural than MoveFrom -- though I can imagine implementing both for completeness.

Conceptually, it feels to me like neither collection instances nor the entity being moved is "responsible" for the moving, and that might incline me to put this as a static method -- otherwise you are imparting some extra importance to one of the three things in operation.

Constructing a Holder to then accomplish the move seems pretty excessive.

But it's up to you really, and more knowledge of how these things will be typically consumed may inform what the "right" solution is.

phillipwei
The reason I asked was not linguistic, was exactly about responsibility. Thanks for your opinion. Btw, the Holder already exists, I would only be adding functionality to it.
Martinho Fernandes
I've been detailing other parts of the system and I came to the conclusion it should be the Holder doing the move, since it will also perform some validation, because some entities cannot be moved to Bar.
Martinho Fernandes