From: Brendan Guild on
I have a rather awkward problem domain and I have found a potential
solution, but it is rather tentative and unsettling. The problem with
it is that it exposes member variables almost directly to the user,
almost as if they were public.

The domain I am dealing with is an adventure game that involves many
various items and creatures. Each item or creature will have many
properties that make it distinct from the others, but the nature of
these properties is not all known in advance.

The entities in the game will move around and have interactions which
will be affected by the properties of each entity in some manner and
each interaction might make use of any fixed set of properties, up to
all the properties.

Enough of these properties and interactions are known to make a
working implementation, but it is guaranteed that new properties and
interactions will be created in maintenance, enough so that I cannot
depend on any fixed set of properties.

The natural solution is to represent each of these amorphous entities
as an object and the properties of each object are dictated by the
class of the object. Using many classes all the possible combinations
of properties needed for the game can be created, and of course many
more classes would be added in maintenance.

Unfortunately, I don't know which entities will interact with which
and I have no means of creating a reliable class hierarchy to
organize them. In each interaction, each entity would need to be
dynamically analyzed to determine which class it belongs to so that
its properties could be accessed. I might do that with the visitor
pattern or a switch statement, but I found another way.

Since I cannot make any reliable relationship diagrams between the
entities, I represent them all as objects of a single class, like
this pseudocode:

class Entity {
Object get(Property);
void set(Property, Object);
}

In Entity I replace a potentially very large number of getters and
setters by a single parameterized pair. Entity has no encapsulation
and no real methods, but the great thing about it is that its public
interface will never have to change during maintenance.

The Property class is completely featureless, with no members of any
sort, so creating new properties is trivial.

At first I thought that this was a horrible design because it is
making everything public, but then I realized that the member
variables are not truly public because they can only be accessed when
the correct Property object is available. Since I will not be making
the Property objects globally available, what can access what will be
very strictly controlled.

Then I realized that I could create more complicated properties that
behave just like ordinary properties in that they get and set values,
but they are actually composed of other properties and use them to
compute a derived property. That realization suddenly makes this idea
all the more interesting!

Does this match some design pattern that I should know about? Is it
just a horrible idea?
From: H. S. Lahman on
Responding to Guild...

How refreshing to have an actual problem description on this forum
rather that some fragments of solution code...

> I have a rather awkward problem domain and I have found a potential
> solution, but it is rather tentative and unsettling. The problem with
> it is that it exposes member variables almost directly to the user,
> almost as if they were public.
>
> The domain I am dealing with is an adventure game that involves many
> various items and creatures. Each item or creature will have many
> properties that make it distinct from the others, but the nature of
> these properties is not all known in advance.
>
> The entities in the game will move around and have interactions which
> will be affected by the properties of each entity in some manner and
> each interaction might make use of any fixed set of properties, up to
> all the properties.
>
> Enough of these properties and interactions are known to make a
> working implementation, but it is guaranteed that new properties and
> interactions will be created in maintenance, enough so that I cannot
> depend on any fixed set of properties.
>
> The natural solution is to represent each of these amorphous entities
> as an object and the properties of each object are dictated by the
> class of the object. Using many classes all the possible combinations
> of properties needed for the game can be created, and of course many
> more classes would be added in maintenance.

Right. Trying to organize Entity into a generalization relationship
would probably lead to a combinatorial explosion of subclasses. If you
delegate properties

1 R1 possesses *
[Entity] ---------------------- [Property]
A
|
<subclasses>

your generalization tree is limited to flavors of [Property] and the R1
relationship captures the notion of a collection of a specific set of
Properties for a given Entity.

[Caveat. There is potentially a problem with the '1' multiplicity for
R1 because the same properties might be relevant for different entities.
However, I am guessing that Property instances are likely to have
attribute values that are unique to the Entity they are associated with
(e.g., a Skill system for the Entity can modify the Property values).]

>
> Unfortunately, I don't know which entities will interact with which
> and I have no means of creating a reliable class hierarchy to
> organize them. In each interaction, each entity would need to be
> dynamically analyzed to determine which class it belongs to so that
> its properties could be accessed. I might do that with the visitor
> pattern or a switch statement, but I found another way.

Good. B-)

>
> Since I cannot make any reliable relationship diagrams between the
> entities, I represent them all as objects of a single class, like
> this pseudocode:
>
> class Entity {
> Object get(Property);
> void set(Property, Object);
> }
>
> In Entity I replace a potentially very large number of getters and
> setters by a single parameterized pair. Entity has no encapsulation
> and no real methods, but the great thing about it is that its public
> interface will never have to change during maintenance.

I assume that "Property" in the pseudo code is actually a property type
code while "Object" is a reference to a property instance.

Basically you are implementing a variation of the R1 relationship above.
The get/set operations would actually be methods of the R1 collection
class, which would be a member of [Entity]. Assuming there is at most
only one Property instance for each property type, then the R1
collection class would own the smarts for finding the right one. That
provides separation of concerns and encapsulation.

Without further information I would be inclined to simplify the setter
by making a [Property] have a type attribute and specializing the R1
collection class to be able to access that attribute to do its search
(or provide an ordered list). Then the setter only needs the Property
reference. That would allow the actual client to add properties to an
entity without knowing what they were. I don't know whether that would
be attractive in you particular game.

>
> The Property class is completely featureless, with no members of any
> sort, so creating new properties is trivial.

I am missing something here. How can a Property be featureless if there
seem to be different flavors (i.e., there is a "new" property)? There
has to be something to distinguish, say, a Spell property from a Sword
property.

[Note that this sort of flavorizing of properties is pretty common in
games. One bundles a suite of attributes for things like Combat and
Movement properties. That sort of structure is clearly reflected in the
modding configuration files for games like CIV.]

>
> At first I thought that this was a horrible design because it is
> making everything public, but then I realized that the member
> variables are not truly public because they can only be accessed when
> the correct Property object is available. Since I will not be making
> the Property objects globally available, what can access what will be
> very strictly controlled.

Right. R1 is just a relationship that restricts what properties a
particular entity has. Whoever uses the getter necessarily has a
context where collaborating with the property is important. The R1
collection class now owns the responsibilities for ensuring correct
access (responding NO_SUCH_PROPERTY) and locating particular properties.

However, I would point out that the client of the getter is someone who
needs to collaborate with a specific Property, not the Entity itself.
So what one really has is:

[Client]
| 1
|
| R2
|
| accesses properties of
| *
[Entity]
| 1
|
| R1
|
| possesses
| *
[Property]

The collaboration path is really R2 -> R1 where [Entity] is basically
just a placeholder node on the path. Thus the semantics of [Entity] is
not relevant to whatever the Client wants to do with the Property.

Your application will generally be more robust if you make relationship
implementation and navigation orthogonal to the act
From: Daniel T. on
Brendan Guild <dont(a)spam.me> wrote:

> I have a rather awkward problem domain and I have found a potential
> solution, but it is rather tentative and unsettling. The problem with
> it is that it exposes member variables almost directly to the user,
> almost as if they were public.
>
> The domain I am dealing with is an adventure game that involves many
> various items and creatures. Each item or creature will have many
> properties that make it distinct from the others, but the nature of
> these properties is not all known in advance.
>
> Does this match some design pattern that I should know about? Is it
> just a horrible idea?

It sounds to me like you are looking at the problem from a non-OO
perspective. How about this problem description instead.

Your domain involves characters that can do a limited number of things
(move, fight, pick-up, drop.) The items that a character is carrying
modify its ability to do those things in various ways.

class Character:
def acquire(self, item):
self.items.append( item )

def move(self, location):
if self.canMoveTo( location ):
self.doMove( location )

def canMoveTo(self, location):
result = false;
for item in items:
result = result or item.affectMove( self, location )
return result

def doMove(self, location):
"actually move the character"

--
There are two things that simply cannot be doubted. Logic and our
ability to sense the world around us. Doubt those, and you no longer
have anyone to discuss it with, nor any ability to discuss it.
From: Rick Elbers on
Op Tue, 05 Sep 2006 11:12:03 GMT schreef "Daniel T."
<daniel_t(a)earthlink.net>:

> Brendan Guild <dont(a)spam.me> wrote:
>
>> I have a rather awkward problem domain and I have found a potential
>> solution, but it is rather tentative and unsettling. The problem with
>> it is that it exposes member variables almost directly to the user,
>> almost as if they were public.
>>
>> The domain I am dealing with is an adventure game that involves many
>> various items and creatures. Each item or creature will have many
>> properties that make it distinct from the others, but the nature of
>> these properties is not all known in advance.
>>
>> Does this match some design pattern that I should know about? Is it
>> just a horrible idea?
>

This matches "many various" design patterns.

>It sounds to me like you are looking at the problem from a non-OO
>perspective. How about this problem description instead.
>
>Your domain involves characters that can do a limited number of things
>(move, fight, pick-up, drop.) The items that a character is carrying
>modify its ability to do those things in various ways.
>
>class Character:
> def acquire(self, item):
> self.items.append( item )
>
> def move(self, location):
> if self.canMoveTo( location ):
> self.doMove( location )
>
> def canMoveTo(self, location):
> result = false;
> for item in items:
> result = result or item.affectMove( self, location )
> return result
>
> def doMove(self, location):
> "actually move the character"

> There are two things that simply cannot be doubted. Logic and our
> ability to sense the world around us. Doubt those, and you no longer
> have anyone to discuss it with, nor any ability to discuss it.


How many logics we know about ?

About the "ability to sense the world around us"

Hume will applaud to you. Alas "the great doubter" wouldnt. And he is
more famous:-)

Rick

From: Brendan Guild on
H. S. Lahman wrote in news:E%YKg.14590$%_1.641(a)trndny07:
> Responding to Guild...
>> Since I cannot make any reliable relationship diagrams between
>> the entities, I represent them all as objects of a single class,
>> like this pseudocode:
>>
>> class Entity {
>> Object get(Property);
>> void set(Property, Object);
>> }
>>
>> In Entity I replace a potentially very large number of getters
>> and setters by a single parameterized pair. Entity has no
>> encapsulation and no real methods, but the great thing about it
>> is that its public interface will never have to change during
>> maintenance.
>
> I assume that "Property" in the pseudo code is actually a property
> type code while "Object" is a reference to a property instance.

Yes, exactly. I realize that despite my care I somehow managed to
still assume some domain knowledge when writing my problem
description.

Each property of an entity is like a member variable of a class. I
hadn't considered calling them a property type, but that is what it
is. For example, one might have a property type called 'height' and a
property instance of that type such as '6 feet tall'. Then a better
pseudo-code would be:

class Entity {
PropertyInstance get(PropertyType);
void set(PropertyType, PropertyInstance);
}

And there is an assumption that each entity can have at most one
property of each property type at any time. In other words, you
assumed correctly but I should have been more clear. Perhaps I should
consider the possibility of having multiple instances of a property
type in a single entity, though I doubt that will be necessary.

The usage of the getter and setter is intended to be much like this:
get(propertyA) is a more general equivalent to getPropertyA()
set(propertyA, propertyValue)
is equivalent to setPropertyA(propertyValue)

Or, alternatively, just like having each property type as a public
member variable of the class entity.

> Without further information I would be inclined to simplify the
> setter by making a [Property] have a type attribute and
> specializing the R1 collection class to be able to access that
> attribute to do its search (or provide an ordered list). Then the
> setter only needs the Property reference. That would allow the
> actual client to add properties to an entity without knowing what
> they were.

In other words, wrapping up the property and property type into one
value. That is certainly an interesting possibility and now that I
recognize my misuse of the word 'property', I realize that it makes
perfect sense to do it that way.

However, property instances and property types would be most often
have to be dealt with separately because no similar simplification
can be made to the getter. Most computations are sure to involve
getting several properties from some entities based on their property
types, then using those properties in some formula and setting the
resulting property to some entity. The property type of the property
to be set will be known well in advance, but the specific property
would have to be computed at the time. In practice, a property that
knows it own type, such as '6 feet tall' would have to be constructed
just before it was set from the number 6 that was just calculated and
the property type 'height'.

>> The Property class is completely featureless, with no members of
>> any sort, so creating new properties is trivial.
>
> I am missing something here. How can a Property be featureless if
> there seem to be different flavors (i.e., there is a "new"
> property)? There has to be something to distinguish, say, a Spell
> property from a Sword property.

Using the terminology that I originally used, a Property had only its
identity and that was all one could use. Now I would call such a
thing a PropertyType. I had considered things like 'height' and
'age' to be properties of people, but of course it is only specific
heights and ages which are properties, while the abstract concept of
height or age is merely a property category containing actual
properties like '6 feet tall' and '50 years old'.

A property type needs no attributes because its only purpose is to
distinguish '6 feet tall' from '6 years old' and to act as a way to
access a value like 6 from an entity as if using a key to access a
value from a hash table.

I distinguish a Spell property from a Sword property by using the
identity of the corresponding property type. The property type is not
connect to the property once the property has been extracted from the
entity, but I can still easily keep track of what sort of property it
is by variable names, comments and execution tracing. For example:

int ageInstance = elderlyPerson.get(agePropertyType)
int heightInstance = elderlyPerson.get(heightPropertyType)

ageInstance and heightInstance are just numbers with no way to
distinguish what sort of properties they represent except lexically
by looking at which property type was used to 'get' them.

I am not entirely certain that I have correctly interpretted your
advice, but I will continue to think about it.

> R1 is just a relationship that restricts what properties a
> particular entity has. Whoever uses the getter necessarily has a
> context where collaborating with the property is important. The
> R1 collection class now owns the responsibilities for ensuring
> correct access (responding NO_SUCH_PROPERTY) and locating
> particular properties.
>
> However, I would point out that the client of the getter is
> someone who needs to collaborate with a specific Property, not the
> Entity itself. So what one really has is:
>
> [Client]
> | 1
> |
> | R2
> |
> | accesses properties of
> | *
> [Entity]
> | 1
> |
> | R1
> |
> | possesses
> | *
> [Property]
>
> The collaboration path is really R2 -> R1 where [Entity] is
> basically just a placeholder node on the path. Thus the semantics
> of [Entity] is not relevant to whatever the Client wants to do
> with the Property.
>
> Your application will generally be more robust if you make
> relationship implementation and navigation orthogonal to the
> actual collaborations needed to solve the problem in hand. To see
> this consider what abstract action language (AAL) code in a UML
> OOA model would look like for the [
 |  Next  |  Last
Pages: 1 2 3 4 5 6 7 8 9 10 11
Prev: Name of construct
Next: Deriving - .NET example