Class Design question

I’m developing a class (ClassA) which behavior will be influenced by another class (ClassB).
Somewhere in a method of ClassA I have to write:

If ClassB.Property1 = False then do this else do that end if

But ClassA doesn’t now how ClassB will be implemented. Moreover, I was always taught that classes should be agnostic of each other. How to solve this?

make a private property in classA named “myclassB” and type ClassB
make a constructor to assign the classB to the classA
refer to the classB with the property myClassB from classA

If we tried to do that, we never get anything done… They should have no knowledge of or reliance on how the other class has been implemented.

So the first thing to sort out: Are you talking about a property of the class or a property of an instance of a class?

If you are referring to a property of the class, then the class must exist, otherwise wise it will not fly.

If you are referring to a property of an instance of class B, then the instance of class A must in some why receive a reference to the instance of class B, either in it’s constructor or as a parameter to a method call on the instance.

In order to handle the fact that the class has not been defined, you need to introduce an interface into the equation, so class A would then interact with the interface rather than class b. Later when you come to create class b, you need to have it implement the interface so it can interact with class A.

This is a perfect situation for the Observer pattern. You can find examples in the Xojo Examples folder.

@Alexander van der Linden — Classes cannot be agnostic of each others. If your class A uses class B, then it has to know how to use it and A becomes dependent on B. That is perfectly normal.

This is not necessary, though possible.
If you use interfaces as the Observer pattern does, the class only know the interface.

@Massimo Valle — True, but one way or another, there must be some exchange about how to use a class, be it

  1. a class declaration
  2. an interface
  3. Introspection (i.e. a dynamic class declaration)

[quote=444005:@Alexander van der Linden]I’m developing a class (ClassA) which behavior will be influenced by another class (ClassB).
Somewhere in a method of ClassA I have to write:

If ClassB.Property1 = False then do this else do that end if

But ClassA doesn’t now how ClassB will be implemented. Moreover, I was always taught that classes should be agnostic of each other. How to solve this?[/quote]

Use an interface
Then have classB implment that interface
An interface is quite literally a contract about how a class will behave but NOT about its implementation of that behaviour
ClassA then has a property that refers to an instance that IS the interface type and you have some API for setting that

Then your code is more like

If ClassB.ShouldDoThat = False then do this else do that end if

and you’re not reaching into the guts of the implementation (ie reading a property)

Thanks all for the response. Food for thought.

It’s a property of an instance of that class. That’s why it doesn’t know what it’s name will be. I haven’t yet worked with interfaces or constructors yet. I could reach my goals perfectly without it.

Interfaces are really simple
Basically when you say a class implements an interface what you are promising is that the class will implement all of the methods of the interface - it can implement others as well but they arent part of the agreed to “contract”
It makes it so that you can swap the actual instance out for a different one as long as they both implement the interface

For instance, suppose you have a bunch of classes that are unrelated so a class hierarchy makes no sense. Maybe there is a class for a Car, and a Horse. A car is not a horse and the horse is not a car so its unlikely they have any relationship in their super classes.

But, both can MOVE. How they move is different.

So they might both implement a “Movable” interface which has one method - Move(inDirection as integer)
We can debate about direction as an integer - but accept that this means “move in a given direction”

So we have

Interface Movable
    Sub Move(inDirection as integer)
End Interface

And then we make Car implement Movable

Class Car
    Implements Movable

    Sub Move(inDirection as integer)
         // in here we write the code for how to move a car
    End Sub

    .... // other methods & properties of a Car
End Class

And Horse implement Movable

Class Horse
    Implements Movable

    Sub Move(inDirection as integer)
         // in here we write the code for how to move a horse
    End Sub

    .... // other methods & properties of a Horse
End Class

Now anything that knows how to tell a Movable to move can use either a car or a horse and really doesnt care which it is
It knows its “Movable”

dim m as Movable

m = new Car
m.move(129)

m = new Horse
m.move(129)

And since an interface IS a new type you can also do things like ISA tests

dim v as Variant
v = new Car

if v isa Movable then
  Movable(v).move(129)
end if

Hi Norman,

thanks. I thinks I grasp the basics. But this is about methods. What I want to share between classes is the outcome of a calculation which is stored in a property in class Horse but is needed in class Car. But class Car doesn’t know if class Horse is implemented as MyHorse of MrEd and I tried already but either way it won’t compile.

make the method in the interface a FUNCTION that returns a value
you still need some reference to the class - whether that is saved as a property in the class relying on the other one or not

suppose Movable includes a “DistanceMoved() as Integer” function
then any things that knows about “movable” can also find out how far the thing moved when told to move

dim m as Movable

m = new Car
m.move(129)
if m.DistanceMoved() < 100 then
    /// .... etc
end if

m = new Horse
m.move(129)
if m.DistanceMoved() < 100 then
   // etc .....
end if

Same for your case

[quote=444097:@Norman Palardy]make the method in the interface a FUNCTION that returns a value
you still need some reference to the class - whether that is saved as a property in the class relying on the other one or not

suppose Movable includes a “DistanceMoved() as Integer” function
then any things that knows about “movable” can also find out how far the thing moved when told to move

dim m as Movable

m = new Car
m.move(129)
if m.DistanceMoved() < 100 then
    /// .... etc
end if

m = new Horse
m.move(129)
if m.DistanceMoved() < 100 then
   // etc .....
end if

Same for your case[/quote]
Works! Thanks

Another question: I have a Canvas subclass in which I already use the Paint event to draw a specific pattern. But I want the Paint event to be available for the user as well. So I added an event definition ‘Paint’ and in the Paint event I do my drawing and I tried to use

Return RaiseEvent Paint(g as Graphics, areas() as REALbasic.rect)

but that won’t compile. How to use the Paint event and make it available again?

Return RaiseEvent Paint(g , areas )

the data type declaration as integer and as REALbasic.Rect are only needed when you first define the method event etc

Tried that:

Event Paint(g as Graphics, Areas() as REALbasic.Rect) As Graphics

Sub Paint(g As Graphics, areas() As REALbasic.Rect) Handles Paint
  
  G.ForeColor = Me.GridColor
  
  For I As Integer = 1 To Me.Width Step (Me.BlockSize + Me.GridSize)
    For J As Integer = 1 To Me.Height Step (Me.BlockSize + Me.GridSize)
      G.FillRect(I,J,Me.Blocksize,Me.Blocksize)
    Next
  Next
  
  Return RaiseEvent Paint(g,areas)
  
End Sub

Compiler error: PlayCanvas.Paint, line 10
You cannot return a value because this method has not defined a return type
Return RaiseEvent Paint(g,areas)

the error tells you exactly whats wrong
the paint event you ADDED can return a value but the PAINT event you implemented in the class cannot RETURN a value

I’m kinda lost here. How to solve this?

change

Return RaiseEvent Paint(g,areas)

to

RaiseEvent Paint(g,areas)

the PAINT event inherited from Xojo classes like canvas etc has NO return value so you cannot return anything

Ahh! Of course. Many thanks