Re: Abstract public member variales?
- From: "H. S. Lahman" <h.lahman@xxxxxxxxxxx>
- Date: Sun, 10 Sep 2006 17:17:07 GMT
Responding to Guild...
I believe you would be better off dealing with the additions using
subclassing of [Property] and relationships to the subclasses to
ensure the Property was interpreted correctly. That allows the
collection object to deal only with [Property] objects, so it
doesn't need to change when new classes are added.
I have been experimenting with these ideas as we speak. I have tried to avoid doing it the way you suggest because I felt that casting was always a bad idea, but avoiding it in this case was causing me problems. So, I am quite happy to conclude that you have the best idea here; casting is appropriate in this case.
I agree with you that casting is usually not a good idea. In this case it is fairly benign because one has taken pains to ensure that it is done correctly by duplicating the relationship so that one explicitly navigates the right relationship in the code. In general casts based on static structure are less likely go awry than those that depend on dynamics for correctness because static structure tends to be more stable over time.
But even here one is sacrificing some safety because some later maintainer could modify the relationships and the resulting problem would be pretty well hidden.
In the big picture completely replacing the details of how the collection class works internally would be an extremely small job
compared to even the slightest modification to the client. The
client is huge and the collection class is drop in the ocean, so
I am not concerned about that sort of detail.
My first pushback is: why is the client "huge"? That usually
indicates a god or controller object, which is a no-no in a
well-formed OO application.
Perhaps it is a my misinterpretation of your terminology, but when I used the word 'client' I did not strictly mean some object that uses the entity. To me, a client can just as easily be a system of objects as a single object.
OK.
When I said that the client was huge, I meant only that the collection class represents a very small amount of my effort relative to all the places in which it will be used. Even though the collection class will have instances throughout the design, the collection class alone does not even begin to solve the domain problem; it is merely a vital tool.
So the client is very large because the client represents the entire solution while the collection is one vital and frequent but small piece.
OK. But that is an argument for keeping the collection interface simple. If there are potentially many contexts where a Property needs to be accessed, it becomes difficult to predict exactly why it is needed. That is pretty much why peer-to-peer collaboration is mandated in OOA/D -- you want to deal with collaboration on a context-by-context basis. If the collection interface sticks to the very generic task of list management, then it remains independent of the context of access of Properties.
I am concerned by the techniques that you have offered that use a runtime security check:
The downside, of course, is that the client needs to be able to gracefully accept refusal of its request if it asks for a property
that it should not have access to. That may get a bit tricky in
an asynchronous environment where there is no immediate error
return.
This seems like an awfully serious downside, especially when we have techniques available that make it impossible for the client to ask for such a property.
There are a couple of philosophical issues here. So get a six-pack and get comfortable...
My first point is that you would probably have that problem anyway. Given the way we are talking about accessing Properties via a PropertyType value, one way the Client is going to access a Property it shouldn't have is because of a software bug and you are going to have to deal with that anyway. The only other way to go awry is for the Client to /ask/ for the wrong property type, which is what you are trying to protect against. I address that in the third issue below.
My second issue is related to how much trouble it is to deal with a refusal in an asynchronous solution. In OOA/D knowledge and behavior are treated very differently. The main way that is manifested is in the execution model for access that the developer assumes. Knowledge attributes are assumed to be accessed synchronously (i.e., the caller pauses execution until the value is provided). Behavior access, OTOH, is assumed to be asynchronous (i.e., the message sender continues to execute after the message is sent and may complete before the response even begins). There are two reasons for this.
The first is that message and method are separated in OOA/D so there is potentially a delay between when a message is generated and when a response is executed. The second reason is that an asynchronous behavior model is the most general (i.e., a synchronous implementation is a special case of asynchronous where the order of messages is predefined). That is, an asynchronous model can always be implemented in a synchronous environment without change but a synchronous model usually cannot be implemented in an asynchronous environment without modification. [The OOPLs are inherently synchronous because they are 3GLs based on procedural message passing and stack-based structure. So the OOA/D is also providing some independence from the 3GL level of abstraction.]
So my second point is that a proper OOA/D solution will already be asynchronous so it is guaranteed to work if there is a refusal. IOW, that comes "for free" with good OOA/D construction. All you would have to do is recognize that a refusal could happen and provide support for that in the Client. (In your case that would probably be throwing an exception since it shouldn't happen.)
My third issue is the reason that one wants to prevent Clients for accessing certain properties. In reality the developer is deciding what properties clients can access and the developer can screw that up anyway by using the wrong interface, etc.. For that reason I regard language-based information hiding mechanisms as more of a message to future maintainers that says, "I had a reason for restricting access in this context. Before you open up that access you had best figure out what that reason was." IOW, one should use such mechanisms when a potential problem _already exists_ (i.e., something rude will definitely happen if other Properties are accessed in this context).
For example, consider an Employee object where you want to restrict access to salary information for certain clients. Suppose you do that by defining an interface that doesn't provide getters for salary attributes. Does that prevent a maintainer who decides it is necessary to access salary attributes from doing so? No; all the maintainer needs to do is change a declaration in the client. All you are really doing is reminding the maintainer to think about whether those salary attributes should be accessed in that context.
I submit that situation usually does not exist for most collaborations, especially knowledge collaborations, because it is usually painfully obvious what attributes the client needs to access to do its job. That is, one really doesn't have a choice. Conversely one does not access attributes that one does not need.
For example, suppose you have some context where the Client needs an AVProperty. You can provide an interface that hides MVProperties. But do you really need to do so? Your Client can't access MVProperties because you are only using PropertyType values in the accessor that map to AVProperties. Now suppose during maintenance you decide this particular Client also needs to access an MVProperty. Is that wrong in your game context? Probably not because the maintenance is driven by a change you need to make (i.e., you have already decided this particular client context needs to be modified) and there is no compelling reason to believe something /inherently/ bad would happen if the Client accessed an MVProperty. So you are actually making extra work for yourself (changing the interface declaration) during maintenance if you hide certain attributes.
So what's the difference between the Employee example and the AVProperty example? External requirements. In the Employee case there is a business requirement that says certain attributes should not be accessed except in a privileged context. [Obviously your game might have similar requirements if, say, it is multi-player and you don't want one player "seeing" another player's information. But my point here is that most solution collaborations don't have such constraints.]
That segues to my next issue: "soft" vs. "hard" access prevention. I regard mechanisms like restricted interfaces as "soft" because they are trivial to modify by the maintainer working on the Client's method. That contrasts with a separate privilege infrastructure where changing the privileges requires explicit surgery in other objects or external data. [In extreme cases in some financial institutions the configuration data for privilege is encrypted so that most of the developers working on the software can't change it. That's really "hard". B-)]
While this is admittedly controversial, I belong to the camp that believes that if access limitations are defined in requirements, they should be addressed by "hard" mechanisms that are explicit in the design and not left as an exercise for OOP manipulation of language-dependent type systems. The corollary is that the "soft" mechanisms then aren't really very useful because they would only apply to ordinary collaborations that are driven by the solution (i.e., one does what the solution demands).
My final point has to do with the nature of your Properties. So far they seem to be knowledge attributes of Entity. That is, they only become first class objects because they are dynamically assigned to an Entity. Knowledge attributes are accessed by behaviors that need their values for computation (or who are responsible for updating them). What knowledge the behavior needs is driven by what the behavior does, which is defined by that behavior's responsibility specification.
My point here is an amplification of what I said above when I mentioned that you don't have a choice about what Properties to access. That is essentially determined when you define the Client method's responsibility. But in an OO context we abstract responsibilities from /intrinsic/ characteristics of a problem space entity. So there isn't a lot of wiggle room. Once we accept the responsibility abstractions, we are pretty much stuck with delivering the knowledge that they need.
Note that we deal with privilege requirements when we abstract the responsibility. Those requirements are reflected in the way we tailor the responsibility definition to the problem in hand. So we can't define the responsibility in any way that would require it to deal with salary information if it doesn't have the right privilege. Consequently that behavior would have no reason to /ask/ for salary attributes.
So for knowledge attributes it is difficult to justify information hiding in a correct application, which is why one hears a lot more about implementation hiding. Where one primarily uses such mechanisms is to protect against software errors when the price of a developer mistake extends beyond the application, which is another reason why I think one should use "hard" mechanisms if privilege is an external requirement. That is, you don't want software errors, so you should make it as difficult as possible to commit them.
Also note that this last argument does not apply at all to behavior responsibilities. Restricting access to behaviors is quite often driven by the side effects of their updating knowledge attributes. IOW, quite often you /must/ restrict access to behaviors to ensure a correct solution.
Having said all this I now have to push back and ask: Why do you feel you need to restrict access to Properties?
Changing the state of a property with 'set' or changing the relationships between an entity and its properties with 'add'
have very little difference. I have no intention of making the
identity of properties important, so only their content matters.
If I change the property of a gnome's height from 4 feet tall to
10 feet tall by altering the number contained in the property or
by replacing the '4 feet tall' property by a '10 feet tall'
property, the change will have identical semantics.
It appears that we have a major disconnect here. Previously when
you talked about this I didn't take this view of 'property'
seriously because I saw '4 feet tall' as just a text string value
to substitute for a numeric value of 4. (In OOA/D where I hang
out this is not an issue because one always uses ADTs that
abstract away such OOP implementation issues.) However, I have to
conclude that you really do see '4 feet tall' as a different
property than '10 feet tall'.
Surely that is not very surprising. Setting aside whatever I might want the class Property to represent in my design, just using the natural meaning of the word 'property', the property of being 4 feet tall is very different from the property of being 10 feet tall (6 feet different, in fact!) The connection between them is not that they are the same property, but that they are of the same property type which I would call 'height'. I know that the word 'property' is rather vague, but I had thought we were using it in the same way.
OK, but I think the OO paradigm is pretty clear about how it defines a property. An object property is a responsibility to know or do something. In your case the properties all seem to be knowledge responsibilities so far. That 'something' then identifies the property, like 'height' for a knowledge attribute. The value of the property distinguishes what the objects sharing that property actually know.
So being 4 feet tall is not a different property than being 10 feet tall in OO terms. It is simply a different value of the same knowledge responsibility.
If so, I'm afraid I can't agree. If that were true and you had 40
Gnome instances, each of different height you would need 40
different properties.
Surely this cannot be avoided. How else would you put the varying information of their heights into the corresponding collection objects? 40 different heights must be represented by 40 different objects, each containing a different number to indicate the actual dimensions of the gnome. Since those objects are called 'properties' and they are of the Property class, that makes 40 different properties.
What I am now wondering about is why we need A-V pairs or any other dynamic assignment of properties at all. Why isn't 'height' an attribute of Gnome? Then you can have 40 gnomes with the single 'height' property that are of 40 different heights. Instead of "assigning a property" you just need to assign a suitable value to the single existing attribute of each Gnome.
The problem I originally thought you were dealing with was that Entity could have certain properties like skills were not inherent to Entity and could be dynamically added. This is beginning to sound more like a basic subclassing problem where an Entity could have subclasses for Gnome (where 'height' is relevant) or Chariot (where 'model' is relevant).
So now I am concerned whether there is any dynamic assignment of Properties to Entities at all. Do you have any properties like
"height" or "weight" that some Entities have and others don't or
which are added dynamically to an Entity at run time?
I presume that you mean property types when you say 'properties', since that is what the abstract concepts of 'height' and 'weight' are and your question makes more sense if I give it that interpretation.
Certainly most property types will be completely absent from most entities. For example, a pillow would have no property of sharpness and a wagon wheel would have no properties for nutritional value and a rock would have no property for intelligence.
OK. Then I would question whether you want to derive everything from Entity. That tends to lead to very large, very complex, and very fragile subclassing trees. Nor do I think dynamic property allocation for a single Entity is the way to go. (In general; I could still see a use for it for some special things like Skills that may not be inherent properties.)
Instead I would look to provide multiple generalizations with 1-3 levels where the root superclass provided a lot of common properties. For example, Weapon, Monster, Furniture, Character, etc. as separate, independent generalizations rather than trying to capture everything in a single Entity. That allows you to use the more conventional attribute mode for things like 'height' or 'sharpness' that are inherent to certain groups of objects. At the same time participation in collaborations is limited to only the entities in a particular generalization (and by direct subclass relationships, as necessary for specialization access). Then if you do need a few dynamic attributes like skills, those can be limited by which generalization they can be attached to (e.g., Rocks won't have attached Skills).
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
hsl@xxxxxxxxxxxxxxxxx
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info@xxxxxxxxxxxxxxxxx for your copy.
Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH
.
- Follow-Ups:
- Re: Abstract public member variales?
- From: Brendan Guild
- Re: Abstract public member variales?
- References:
- Abstract public member variales?
- From: Brendan Guild
- Re: Abstract public member variales?
- From: H. S. Lahman
- Re: Abstract public member variales?
- From: Brendan Guild
- Re: Abstract public member variales?
- From: H. S. Lahman
- Re: Abstract public member variales?
- From: Brendan Guild
- Re: Abstract public member variales?
- From: H. S. Lahman
- Re: Abstract public member variales?
- From: Brendan Guild
- Re: Abstract public member variales?
- From: H. S. Lahman
- Re: Abstract public member variales?
- From: Brendan Guild
- Abstract public member variales?
- Prev by Date: Re: what's the future of Object Oriented Programming
- Next by Date: Re: Abstract public member variales?
- Previous by thread: Re: Abstract public member variales?
- Next by thread: Re: Abstract public member variales?
- Index(es):
Relevant Pages
|
|