|
Prev: Name of construct
Next: Deriving - .NET example
From: Brendan Guild on 14 Sep 2006 19:32 H. S. Lahman wrote in news:dAjOg.11713$xC3.3610(a)trnddc06: > Responding to Guild... > > The problem is reading the attributes because they are not in > [ConcreteA], they are in [ObjectA]. So the saveIt() method in > ConcreteA must navigate the R1 relationship to get to them rather > than the 'this' pointer. If R1 is implemented as a pointer, then > the address of that reference with be exactly the same as the > address provided by the 'this' pointer. The only difference is > that the 'this' pointer in Serializer is hidden while the R1 > pointer in the deconstructor approach must be explicitly > implemented, instantiated, and navigated. > > In the Serializer case somebody had to "walk" the objects in > [ObjectA] set and invoke the Serializer's saveIT() (or whatever) > protocol method for each object. Somebody has to do the same > thing for the deconstructor approach. When they do so, they must > instantiate the R1 pointer to the current ObjectA in hand before > invoking saveIt() to be sure saveIt() gets the right attribute > values. If I understand this correctly, the ConcreteA class will have only one object and the persistence encoding algorithm walks through the relationships of the objects to be encoded. Each time it encounters an object it finds the appropriate 'saveIt' object, i.e. the lone instance of ConcreteA or ConcreteB or ConcreteC, depending on the class of the object to encode and using dynamic cast if polymorphism is involved. Earlier, you said, "When you read the object type you can instantiate the R1 relationship so that ObjectA is processed by the ConcreteA deconstructor when saveIt() is invoked. Essentially what you have done is moved the polymorphic dispatch from the object to be saved into a GoF Strategy pattern." I am sure that the Deconstructor class and its subclasses are the strategies, even though the GoF specifically say that the Context object has a reference to its strategy. But I cannot see where polymorphic dispatch is involved here. I presumed that it had been sacrificed when we abandoned the Serializer pattern to avoid coupling with the persistence. Assuming that you literally meant that the Decontructor was following the Strategy pattern and therefore each ObjectA must have a reference to the unique ConcreteA, then I have another interpretation of your words: the factory does choose which Deconstructor goes with each object and stores it in a reference for the life of the object, to be used by the persistence algorithm and eliminating the need for dynamic casts. I suspected that was what you intended, but I made the leap to assuming that each ObjectA would get a distinct ConcretaA. The intentions are identical though one needlessly costs more in time and memory. In fact, I think this entire technique for persistence could be simply described as the Serializer pattern, but with the implementations of the 'Serializable' interface removed from the actual Serializable class and into another object by using the Strategy pattern. That is very close to what you said, but I was confused by the idea of moving the polymorphic dispatch, since the polymorphic dispatch is not actually being moved but destroyed. It is the implementation of the methods that is being moved. It is interesting that this seems like something you could call a poor use of the Strategy pattern, since every object of any particular persistent class will share just one strategy object for the entire execution of the software.
From: Brendan Guild on 14 Sep 2006 22:27 I think you have lead me to a fundamental realization about my domain that should revolutionize my design. I will explain my thoughts on this matter below. H. S. Lahman wrote in news:LWiOg.2317$yc4.1371(a)trndny01: > Responding to Guild... > > Basically what I am hearing here is that you want to make this > game up as you go along developing the software. I don't think > that works. > > All software needs requirements and all software developers need > to understand the problem domain /before/ the software can be > built. Here the problem domain is a fantasy realm. You have to > have a clear idea of how that realm works (i.e., what the > requirements are) before you start designing software. Even so, the fact remains that large areas of the domain are fluid and uncertain. I know for a fact that no matter how carefully I plan the initial design I will need extensive maintenance. Surely you are not suggesting that it is impossible to create software under those conditions. Even though this is only a game, I cannot change the domain. So the question is, what is the best way to use OO design to assist me? Though I would not have worded it this way, until now my plan has been to use an extremely abstract entity objects. For each one I would represent physical properties as a collection of 'Property' objects which are also extremely abstract, holding only a data value and a 'PropertyType' reference to provide the semantics of the value. The behaviour properties of the entities would be represented by a fixed set strategy objects which polymorphically dispatched event messages to low-level entity manipulation methods. I could implement my entire design in this way by creating strategies until all the desired entities were behaving as desired, with no difficulty in adding or modifying entities except for the complexity of working on such a low level. Through reading this thread, I have come to realize exactly what I need. Primarily, I need extremely high decoupling between entities. It is a priority above all others that I should be able to add or modify entities at will in any manner that satisfies the very primitive fundamental structure of the domain without forcing even the slightest modification to other entities. Towards this goal, each entity becomes like a subsystem with the properties acting as the data interface, though it is data by reference to accommodate the necessity of entities modifying each other's properties. Also, entities will naturally share classes and stateless objects, but otherwise they will be quite separate. Now the only problem is to overcome the complexity and maintenance nightmares of dealing with the low-level property manipulation. I suspect that this should be dealt with using your idea of role objects. The only place lacking abstraction currently is within the implementation of the entity behaviour, so let it be dealt with independently. The behaviour strategy for each entity can assign roles to each entity that it interacts with by wrapping the bare Entity objects in more meaningful Role objects, such as Weapon, Monster, Furniture, etc. Just as you suggested, when a Monster picks up a Jaws to attack with, the Jaws will be wrapped in a Weapon object because it is now conceptually a weapon. The Weapon object will implement some or all of the low-level property manipulation that goes along with using a weapon but in an abstract way. No other Entity object needs to know about the existence of the Weapon object. I can use object-oriented design within the implementation of an entity or even a large group of entities to greatly simplify the otherwise low-level implementation, but that design is to be encapsulated to always a subset of entities. If I find that my abstractions and generalization for my current entities are not allowing me to create a new entity which I need, I can implement that new entity entirely independently with a completely different object-oriented design. This requires that the strategy objects will often carry state to maintain their individual abstract views of the situation between events. This state will be partially redundant with the state contained in the entities themselves, but the strategy state will be far more advanced and detailed, giving roles to entities which do not otherwise have roles. While it is true that one needs to know what is being designed before design can begin, I hope to design each group of entities as independently as possible and I think that something similar to the above is the way to do that. >> In an adventure game the thing that is being simulated is as >> complicated as everyday life. It is people and creatures >> interacting and fighting, collecting objects with magical >> effects, etc. The variety of things that can happen is so large >> that it is impossible to grasp the fundamentals, just as there >> are no fundamental rules of what people can say and do in life. >> (Aside from the obvious ones, but even those are lifted in a >> fantasy game.) > > All commercial simulations abstract everyday life. That's what > they do -- extract basic fundamentals from myriads of complex > interactions. They abstract things which exist in reality, but that is not what I meant by 'everyday life'. I was hoping to convey connotations with that term when I should have made more explicit. I actually meant personal interactions between people and objects such as friendships, employment, tools, clothing, buildings, the full range of objects that an average individual would consider important during the course of a single day, but nothing beyond that such as planets and molecules and weather patterns. Even those people who are concerned with the tanker charter market would not consider it to be important in the span of a single day. It is important in a span of years, over changing economic conditions, and perhaps over months with changing gas prices, or even from week- to-week in the salary of tanker employees, but it is not important just for getting through a day.
From: Brendan Guild on 15 Sep 2006 14:19 Dmitry A. Kazakov wrote in news:1eqtbrnri1fcy$.yl9831mjokfa.dlg(a)40tude.net: > On Tue, 12 Sep 2006 18:22:05 GMT, Brendan Guild wrote: > >> It depends on what you mean by similar. All properties >> represented by numbers will be of the same type in the language, >> and so will all properties represented by strings. I do not think >> there is any benefit to creating more detailed types than that. > > Benefits are huge: > > 1. OO programming. You can't define different method on the same > type It has not been made clear why I might want to dispatch on the class of a property. Properties are data objects for use by methods expecting data of a certain type; I cannot imagine a situation where there could be a choice about the type of the data, so I cannot see a benefit to overloading on that type. > 2. Static type checks My properties will be drawn out of a collection, so their specific subclass will be dynamic. Therefore, no matter how many subclasses there are there will be no static type checks. >> But each property type has different semantics and is used in a >> different way and known about by different objects. > > = it is not single dispatch. When semantics sufficiently depends > on both the type of Entity and the type Property that is > equivalent to MD. Could you expand upon that? MD can only exist in a method call, if I understand it correctly, but it is not clear what method call you are refering to. >> A property does not know about entities, but there is an >> outsider, called 'the client' who chooses an appropriate >> behaviour for the entities. The client works with some >> properties, entities work with other properties, and different >> entities work with still other properties. > > And how the outsider decides when it makes what? If the decision > is based on the types of Outsider, Entity and Property, that is > triple dispatch. If the decision is based additionally on the > values of, that is a total ad-hoc mess. No decisions are made based on the type of Property. It does not make sense to use 'Property' as a proper name like that unless you are talking about the Property class, in which case there is only one type. The reason is that every decision will involve multiple properties. Each individual property has its own type, but there are many properties, not one Property, and in all the places were decisions are made the types of the properties involved are fixed while the values are used to calculate the results. On the other hand, the type of the entity and the type of the outsider are indeed used to make decisions, but only one of them for each decision.
From: H. S. Lahman on 15 Sep 2006 15:27 Responding to Guild... >>What I am arguing against is the alternative that you seem to be >>suggesting where all entity properties are dynamically added >>rather than being intrinsic properties. In effect Entity then >>becomes an abstraction that is so abstract that it only has two >>properties: identity and a type. (You need the type to enforce >>whatever rules exist to add properties to a specific entity.) >>That's fine, but it has a huge drawback in an OO context. It does >>not reflect the intrinsic structure of the problem space. > > > Entities also have position in the simulated environment, and I think > we should count the 'properties' collection as a property of the > entities. > > I am seriously not certain that there is very much intrinsic > structure to this problem space. These are the things that I can > currently say with absolute certainty about the problem space: > > There is an environment that is represented by one or more two- > dimensional grids of environment elements. At any moment there is a > set of entities and each entity has a unique position, either as > coordinates in the environment or within or upon another entity. It > is possible to navigate positional relationships from any entity > through any number of other entities to finally find coordinates in > the environment. The set of entities and the positions of those > entities can change from moment to moment, as can any particular > environment element, but there will always be at least one entity and > there will always be an environment element for every point on every > grid. I would expect the graphic representation is an entirely different view of the entities than the game context view. Its abstractions would be driven by the graphic algorithms and display paradigm, not game semantics because it is an entirely different problem space. It would normally be in a different subsystem. While it may be convenient to have some location information in the game view, the real "owner" of that information would be in another subsystem and you would need some sort of synchronization mechanism to ensure the game view was changed when the graphic (or map) view changed. > I would like to say more, but I have deliberately excluded saying > anything that is not fundamentally true of the problem space. For > example: What is an environment element? It's a wall, an open space, > perhaps a door, perhaps other things to be added in maintenance. > That's fine, but what is a wall? It is an environment element which > prevents entities from having the corresponding position. Except > that's not true because there will be entities that can move through > walls. There are a very large number of things which I know will be > true in almost all cases, but there will also be a very large number > of exceptions. Then the semantics of the 'wall' abstraction changes. In the real world there are bullet proof vests that are a barrier to most ammunition but essentially transparent to full metal jacketed rounds coated with teflon. Does that mean such vests can't be abstracted as bullet proof vests? > I am trying and I will continue to try to think of additional > statements that I know will be invariably true, but an adventure game > thrives on encountering new things and exceptions to rules. I think you have to decide two things before you start developing the software. First, are you developing a single fantasy adventure game or some kind of tool for generating fantasy adventures games in general (i.e., based on external specification of the game)?. If the former, then you have to decide in basic terms what the rules are in your particular realm for the way it works (i.e., what can and what cannot happen there). If the latter, you will have an entirely different set of abstractions than Troll, Wall, and Jaws. (I dealt with this in yesterday's message, so I won't belabor it here.) >>Imagine someone else built such an application and you came in >>cold to maintain it. How would you understand what it was doing? >>How would you understand what the real problem space structure was >>at the moment? Most important of all, how would you understand >>what basic assumptions about the problem space the original author >>had made. It might be easy to add entities and properties but >>just figuring where and how to do it safely would be a nightmare. >>A large part of maintainability is an easily understood >>representation of what is going on _right now_. Without that it >>gets very tough to figure out what to fix. > > > This is a very serious issue and one of great mystery for me. I have > been so concerned about preventing the maintainer from having to make > systemic changes when introducing new entities that the maintenance > issue you raise here never occurred to me. > > What are the ways I can balance these two maintenance issues? I do > not want to start introducing structure upon the problem space that > does not exist there just to simplify the design, but I also do not > want my design to be so nightmarishly complicated that it cannot be > maintained. Perhaps careful documentation is the solution. I think the root problem here is the assumption that maintenance can change the way the game works arbitrarily. It can't. Certain changes don't modify the game; they make it a different game. It may be a fantasy realm but it still needs some set of rules and policies that are invariant, just as our physical world needs the laws of physics to work properly. You have to define that set of rules up front. Then you build the application around them so that you can change the details easily. But changing the fundamental rules once the software is implemented will be a Big Problem and no software methodology is going to avoid that. For example, if some critters can move through walls in your realm, that's fine. But when you allow that you also buy into defining how that happens. Is it an identifiable characteristic of certain critters? If so, is it inherent in the nature of the critter or is it learned like a skill? Or does it require the critter to use some external mechanism? If so, what sort of mechanism (e.g., spell vs. machine)? How does the critter get such a mechanism and learn how to use it? IOW, how your
From: Dmitry A. Kazakov on 15 Sep 2006 15:35
On Fri, 15 Sep 2006 18:19:07 GMT, Brendan Guild wrote: > Dmitry A. Kazakov wrote in > news:1eqtbrnri1fcy$.yl9831mjokfa.dlg(a)40tude.net: > >> On Tue, 12 Sep 2006 18:22:05 GMT, Brendan Guild wrote: >> >>> It depends on what you mean by similar. All properties >>> represented by numbers will be of the same type in the language, >>> and so will all properties represented by strings. I do not think >>> there is any benefit to creating more detailed types than that. >> >> Benefits are huge: >> >> 1. OO programming. You can't define different method on the same >> type > > It has not been made clear why I might want to dispatch on the class > of a property. Properties are data objects for use by methods > expecting data of a certain type; Hmm, you could say something like this about parameters of any subprogram in a typed language... > I cannot imagine a situation where > there could be a choice about the type of the data, so I cannot see a > benefit to overloading on that type. Egh, I don't understand this either. Both overloading and overriding are examples of polymorphism. In both cases the type is the thing that determines the choice. So there is no difference between them in that respect. I.e. the behavior is selected by the actual type (or, more precisely, by a tuple of actual types.) The question is very simple - what determines the behavior of Get and Set? In particular, do the actual types of entity and property influence the choice? If yes, then it is multiple polymorphism. You have a tuple of selecting types. For dynamic polymorphism it is MD, per definition. In the case of static polymorphism (overloading) we silently take "M" for granted, it would be silly to overload procedures only in the first parameter, right? So why the buzz in the dynamic case? >> 2. Static type checks > > My properties will be drawn out of a collection, so their specific > subclass will be dynamic. Therefore, no matter how many subclasses > there are there will be no static type checks. No. Even if you don't always statically know the type, in any real-life program you still know them in 90% cases. So static checks give a huge advantage, because they save 90% of debugging/testing efforts. >>> But each property type has different semantics and is used in a >>> different way and known about by different objects. >> >> = it is not single dispatch. When semantics sufficiently depends >> on both the type of Entity and the type Property that is >> equivalent to MD. > > Could you expand upon that? MD can only exist in a method call, if I > understand it correctly, but it is not clear what method call you are > refering to. "MD in a method" is an implementation of the model, in which a tuple of statically unknown types selects the behavior. You can implement it using a switch statement, or a jump table, if you wanted. That does not change the fact on the ground - you have to select according to more than one type. One of the objectives of problem analysis is to determine if you really have this. I.e. whether the selection could be somehow made on the types involved independently. If it could, then it could be implemented using single dispatch. >>> A property does not know about entities, but there is an >>> outsider, called 'the client' who chooses an appropriate >>> behaviour for the entities. The client works with some >>> properties, entities work with other properties, and different >>> entities work with still other properties. >> >> And how the outsider decides when it makes what? If the decision >> is based on the types of Outsider, Entity and Property, that is >> triple dispatch. If the decision is based additionally on the >> values of, that is a total ad-hoc mess. > > No decisions are made based on the type of Property. It does not make > sense to use 'Property' as a proper name like that unless you are > talking about the Property class, in which case there is only one > type. The reason is that every decision will involve multiple > properties. > > Each individual property has its own type, but there are many > properties, not one Property, and in all the places were decisions > are made the types of the properties involved are fixed while the > values are used to calculate the results. Fixed? You mean, they are statically known or they are somehow derived from the actual type of entity? The first case is static polymorphism in Property x dynamic polymorphism in Entity. It can be easily handled using genericity (templates). The second case is more difficult. It is a parallel types hierarchy - you vary the type of Entity E1->E2 and the type of Property varies coherently P1->P2. > On the other hand, the type of the entity and the type of the > outsider are indeed used to make decisions, but only one of them for > each decision. Yep, this is a equivalent definition of single dispatch (polymorphism). The only question if this is a result of analysis or belief. (:-)) -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de |