哪种设计模式适合这种情况?

So far, most of the objects I've been dealing with look very much like the database tables they are based on. So I have a fish object that maps the db.fish table and a fish_transfer object that maps the db.fish_transfer table, etc.

Now I'm working on a class, Provenance that manages data that doesn't easily map to a single database table. Here's the situation:

Each fish has a provenance, ie information about where it was before it entered our system. There are 4 kinds of provenance: 'unknown', 'delivered', 'bred onsite', 'reuse'. All provenances have a fish_id and a date associated and all except 'bred onsite' require a count to be set immediately. Other than that, they are fairly different in the data associated with them and the actions that must occur on their creation/deletion or change.

I had thought to store the provenance type in the fish object. So, on instantiation, fish would call ProvenanceFactory::make($this->fish_id, $this->ptype) and obtain a provenance object $prov of the correct subclass. So what happens if the provenance type is edited?

Possibilities:

  • call $this->prov->delete() and then $this->prov=ProvenanceFactory::make($this->fish_id, $newtype); $this->prov->setall($data);
  • call ProvenanceFactory::morph(&$this->prov,$newtype); $this->prov->setall($data);
  • call $this->prov->morph($newtype); $this->prov->setall($data);
  • call $this->prov->morph($newtype, $data);
  • ??

In all cases, editing the provenance type results in updating or deleting a set of database rows in various tables specific to the Provenance subclass and then creating another set of rows in various other tables.

Which of the above possibilities (or other) would be the best way to go? What design pattern(s) (other than Factory) should I be trying to implement?

I don't want to suggest remapping everything you have done, however have you considered using Class Table Inheritance.

See : http://martinfowler.com/eaaCatalog/classTableInheritance.html

So in your example your Provenance table and you can use your discrimator coloumn to identify which state the class is in.

how about having a ProvenanceBase class, which has a copy-constructor.
That way, your factory can have a morph method (similar to the 2nd bullet you wrote) which simply creates a new derived object out of an existing derived object.