简体   繁体   中英

What is the best practice for retrieving an item in a collection from a domain model?

What is the best practice for retrieving an object from a collection within a domain object with a specified property?

For example, we have a car insurance application which has two classes: a Person with a list of Cars. If I always needed to retrieve a Car from a Person with the specified VIN, what is the best way to implement the method? I've provided a few examples below - others are welcome

Example 1
Add a new method within the Person entity to retrieve the VIN


    public class Person
    {
         private HashSet<Car> cars = new HashSet<Car>();

         public Set<Car> getCars()
         {
              return this.cars;
         }

         public Car getCarByVin(VIN vin)
         {
              //loop over cars and retrieve the car with the VIN
         }
    }

So from an application the process would be...


    VIN vin = new VIN(...);
    Person person = personDao.getPerson();
    Car personCar = person.getCarByVin(vin); 

Example 2
Create a new list collection within the Person entity and add the retrieve by VIN method to the collection


    public class Person
    {
         private CarSet cars = new CarSet();

         public CarSet getCars()
         {
              return this.cars;
         }
    }

    public class CarSet
         implements Set<Car>
    {
         //implement required methods for Set

         public Car byVin(VIN vin)
         {
              //loop over set and retrieve the car with the VIN
         }
    }

So from an application the process would be...


    VIN vin = new VIN(...);
    Person person = personDao.getPerson();
    Car personCar = person.getCars().byVin(vin); 

I think the Law of Demeter applies here, which favors the first example. Any time you're chaining, such as foo.getBar().doBlah(), that's breaking the Law of Demeter. It's obviously not a law, but it's a good guideline for when a class has to know too many details about the bits within another class.

As soon as you say Car with specified VIN, you make me think this is Entity, not value object... Also, if you need to "retrieve" it that implies that it is Entity, not value. Value objects don't generally need to be retrieved, you can just create one on the fly if you need one... Are you sure you are clear on distinction between entity and value elements in DDD?

ADDED: Then if Car IS an entity, from what you've said, it appears that it should be a member entity in an aggregate with Person as the aggregate root. (Although it may be the root of it's own aggregate) In any case, the Person repository should be constructed so that when you fetch the aggregate it also gets the Cars for that person. The Person class should have a property of Type Cars, or CarCollection, which is named Cars, or OwnedCars, or whatever, and the Type (Cars or CarCollection) should have an indexer that retrieves a specific Car based on the VIN.

public class Person    
{
   private int persId;
   // other fields
   private Cars cars;

   public Cars Cars { get; set; }
   // all other stuff
}

public class Cars: Collection<Car> // or 'public class Cars: List<Car>' or ...
{
    public bool Contains(string VinNumber]
    {
        foreach (Car c in this)
           if (c.VinNumber = VinNumber) return true;
        return false;
    }
    public Car this[string VinNumber]
    {
        get 
        {
            foreach (Car c in this)
                if (c.VinNumber = VinNumber) return c;
            return null;
        }
    }
}

In cases like this, I find it easier to put the search method on the object itself, rather than trying to subclass a collection class (and bringing along all of the design decision changes that can result from that seemingly simple decision).

All of the above assumes that the basic design is really what you want. I'd generally prefer some sort of facade that allows me to search for vehicle by person and vin, rather than searching the person object itself, though.

I really dislike your design with CarSet. I wouldn't like seeing a specialized class for that purpose without specialized behavior; admittedly it's a simple example to demonstrate a point.

But I also object to your Person example. You have a private reference to a HashSet that should have static type of Set. Then you have a getter that returns a reference to that private data member. You should realize that this is a mutable reference that anyone can manipulate. Your private modifier is meaningless.

The right thing to do in that case is to return a reference to an immutable Set, using the java.util.Collections class, to prevent clients from modifying private state.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM