|
From: Veloz on 14 Jan 2008 21:22 Hi there Ultimately I'm trying to figure out if a container class should hold base class references to types it contains, or if it should hold the most specialied class references to the type it contains, in the case that the container class is itself also a user of the contained items (it isn't just a dumb container) Let me explain: I have a class A that acts as a container for one or more instances of classes B, C, and D. B,C, and D all inherit from some class named X. A has two "responsibilities, or relationships" when it comes to B, C, and D: 1. A needs to validate the contents of B, C, and D against each other (to enforce certain business rules). To do this, A really only needs the public interface speciified by X. In other words, A can treat B, C, D all as their base class X, for its purpose of enforcing the business rules. Thus, I could just declare member variables of type X to hold any/all instances of B, C and D: class A { public X _actualClassIsB; public X _actualClassIsC; public X _actualClassIsD; } I like A only knowing the "X"-ness of B, C, D, because it makes it less dependant on the actual final type of B, C, D. BUT: 2. A also acts as a public container for B, C, and D objects, and other code outside A will want to get at B, C, and D through A. This other code will need to access the actual specialized classes B, C and D (i.e., the users of these objects need more functionality that just that provided for by the base-class X). So from this point of view, it seems like A should hold B, C and D through their specific types, as in: class A { public B _actualClassIsB; public C _actualClassIsC; public D _actualClassIsD; } but then A knows more about the types than it needs, and more than I would like. The other alternative is to still have class A { public X _actualClassIsB; public X _actualClassIsC; public X _actualClassIsD; } but then outsiders who need to get a B will have to cast the reference held by A to a more specific type, as in (B)A._actualClassIsB.DoSomethingOnly_B_KnowsHowToDo(); And this seems a bit weird because what it says is that the code outside of A knows more about the actual types contained by A than A itself knows. Does this seem strange to you? So any input on how to best deal with this would be GREAT!! This is a repeating theme across many classes in my app (i.e., objects that are the principal container for some subitem that the container itself also needs to access/use in some way) Michael
From: Daniel T. on 14 Jan 2008 22:43 Veloz <michaelveloz(a)gmail.com> wrote: > Ultimately I'm trying to figure out if a container class should hold > base class references to types it contains, or if it should hold the > most specialied class references to the type it contains, in the case > that the container class is itself also a user of the contained items > (it isn't just a dumb container) > > Let me explain: > > I have a class A that acts as a container for one or more instances of > classes B, C, and D. > > B,C, and D all inherit from some class named X. > > > A has two "responsibilities, or relationships" when it comes to B, C, > and D: Scratch that. Give A only one responsibility and give some other class the other responsibility. Don't put business rules in containers, don't use classes that maintain business rules as containers. > 1. A needs to validate the contents of B, C, and D against each other > (to enforce certain business rules). To do this, A really only needs > the public interface speciified by X. In other words, A can treat B, > C, D all as their base class X, for its purpose of enforcing the > business rules. In order to be able to enforce any invariants between the objects it contains, it *cannot* allow others to arbitrarily change them, therefore they cannot be public.
From: AndyW on 15 Jan 2008 00:52 On Mon, 14 Jan 2008 18:22:45 -0800 (PST), Veloz <michaelveloz(a)gmail.com> wrote: >Hi there > >Ultimately I'm trying to figure out if a container class should hold >base class references to types it contains, or if it should hold the >most specialied class references to the type it contains, in the case >that the container class is itself also a user of the contained items >(it isn't just a dumb container) > >Let me explain: > >I have a class A that acts as a container for one or more instances of >classes B, C, and D. > >B,C, and D all inherit from some class named X. > > >A has two "responsibilities, or relationships" when it comes to B, C, >and D: > >1. A needs to validate the contents of B, C, and D against each other >(to enforce certain business rules). To do this, A really only needs >the public interface speciified by X. In other words, A can treat B, >C, D all as their base class X, for its purpose of enforcing the >business rules. > >Thus, I could just declare member variables of type X to hold any/all >instances of B, C and D: > >class A { > public X _actualClassIsB; > public X _actualClassIsC; > public X _actualClassIsD; >} > > >I like A only knowing the "X"-ness of B, C, D, because it makes it >less dependant on the actual final type of B, C, D. > >BUT: > >2. A also acts as a public container for B, C, and D objects, and >other code outside A will want to get at B, C, and D through A. > >This other code will need to access the actual specialized classes B, >C and D (i.e., the users of these objects need more functionality that >just that provided for by the base-class X). > >So from this point of view, it seems like A should hold B, C and D >through their specific types, as in: > >class A { > public B _actualClassIsB; > public C _actualClassIsC; > public D _actualClassIsD; >} > >but then A knows more about the types than it needs, and more than I >would like. > >The other alternative is to still have > >class A { > public X _actualClassIsB; > public X _actualClassIsC; > public X _actualClassIsD; >} > >but then outsiders who need to get a B will have to cast the reference >held by A to a more specific type, as in > >(B)A._actualClassIsB.DoSomethingOnly_B_KnowsHowToDo(); > >And this seems a bit weird because what it says is that the code >outside of A knows more about the actual types contained by A than A >itself knows. Does this seem strange to you? > >So any input on how to best deal with this would be GREAT!! > >This is a repeating theme across many classes in my app (i.e., objects >that are the principal container for some subitem that the container >itself also needs to access/use in some way) > >Michael > > I got confused about half way down (but I am tired) :) Containers from an OO perspective do not know about what they contain (does a coffee cup know about its contents). But.... The contents knows all about itself. So, I would suggest that your container class really just needs standard container functionality add/find/remove and let your contained items provide their specialist functionality. The other thing I would suggest is have the contained things validate themselves, that way you dont need to put extra functionality into the container code. just my thoughts. ---------------- AndyW, Mercenary Software Developer
From: Dmitry A. Kazakov on 15 Jan 2008 04:23 On Mon, 14 Jan 2008 18:22:45 -0800 (PST), Veloz wrote: > Ultimately I'm trying to figure out if a container class should hold > base class references to types it contains, or if it should hold the > most specialied class references to the type it contains, in the case > that the container class is itself also a user of the contained items > (it isn't just a dumb container) The problem you have is rooted in a wrong mental model of types. The container A does not deal with specialized instances of the class X. It deals with the class itself. Once you clarify this the rest will be easy. Because A holds objects of the class (which is for this reason called polymorphic) it need/can not to know anything else. A polymorphic element knows how to behave. > BUT: > > 2. A also acts as a public container for B, C, and D objects, and > other code outside A will want to get at B, C, and D through A. A cannot know B or C. It only can either. Because this relation were dynamic, you cannot express it as one type. It is impossible to do, and it is also inconsistent. Consider A that contains B, but exposed as containing C. This cannot work. There are three general cases of how a container type could be related to the class of its elements: 1. Specific containers. That is 1-1. Each element type determines a new type of the container. (This is the only way templates can work. In C++ it is like A<B>) Due to static 1-1 relationship container "knows" its element type. A <--> B (member of class X) 2. Polymorphic containers. The element type is of the class. The container knows nothing about specific types. A <--> X (the class as a whole) 3. Constrained polymorphic containers. The element type is of the class dynamically constrained to some range of types from that class. The constraint comes from the container's constraint. I cannot express it in C++, because it just does not posses necessary types mechanics. But 3 is like 2 which can be used as 1 when the constraint is known. A (c) <--> X (c) (c is a constraint) A simple example: array of integers with the element range parameter. When the parameter is constrained to 0..max Integer, then this array is an array of positive. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: Veloz on 15 Jan 2008 09:39
Thanks for all your posts. I wonder if I am confusing people by using the word "container". In my case I am not talking about a language supplied container, such as an array, list, dictionary, etc. I am talking developing a software class (to mirror what's going on in the domain) that holds of a number of other objects. Because this top level class is comprised of ("has") a number of other classes, I refer to it as a container. Maybe I shouldn't do that. Here's a contrived example. The business example is much more complicated, so I hope this weak parallel will make enough sense: Let's imagine that your problem space deals with a concept known as a PartsDrawer. In your domain, the user must define a number of PartsDrawers, each of which can contain: -One Toolbelt, which has several abilities of its own, and contains some woodscrews. -Any number of Magic-Bins, which have several abilities of their own, and contain some wood screws. .... Now, there are a few things I'm trying to accommodate in the design: 1. I would like the design to mimic the domain. As such, I would have a PartsDrawer class that can hold (have/contain) one Toolbelt and any number of Magic-Bins 2. We have a business rule that says the objects put into a PartsDrawer can't have a same colored screw in them. That is, if you have a red screw in a Toolbelt, that's in a particular PartsDrawer, you can't add a Magic-bin to this particular PartsDrawer if that Magic- bin also contains a red screw. .... Now, it turns out, that in the software design Toolbelt and Magic-Bins both inherit from a common class WoodScrewHolder, which provide some common abilities for classes that deal with woodscrews and allows the enumeration of woodscrews held by those classes. The question then becomes: should PartsDrawer decalre variables of type WoodScrewHolder (the base class) to hold the instances of Toolbelt and Magic-Bins, or should the variables be of type Toolbelt and Magic-bins specifically? As far as #2, the business rule about non-repeating colors, I view this as a responsibility of the PartsDrawer. It should prevent things being added to it (the Toolbelt and any number of Magic-bins) which contain the same color screw. To achieve this (the ability to get at and check the woodscrews) PartsDrawer only needs the abilities of the base class, WoodScrewHolder, which allows enumeration over the screws. From this point of view I'd say that PartsDrawer should declare its variables to be of type WoodScrewHolder, so that if the actual items assigned later become more specialized (we end up with a Super-Magic- Bin, which would also inherit from WoodScrewHolder) they could still be assigned to the PartsDrawer without modifying the parts drawer. But here's the kicker to that: Code outside of these classes will want to be accessing the Toolbelt and the Magic-Bin, using their specialized type. That is, this other code can't get it's job done if it has to be constrained to accessing the Toolbelt and Magic-Bin as WoodScrewHolders. If we we declare variables of type WoodScrewHolders in PartsDrawer, this outside code could certainly downcast them to the more specific types (Toolbelt and Magic-Bins) but this feels odd too..Doesn't it seem strange the the outside classes would know the "most specialized" identity of these contained classes while the PartsDrawer only knows them through their most general type? Sorry if this doesn't make sense. This has been a very confusing project for me with all sorts of weird domain relationships.. Michael |