3
\$\begingroup\$

So I have this Pygame 3.3.2 code of 2 classes. I tried to make it as simpler as possible, but ofcourse to show the problems I have with thedesign.

import pygame
import sys

class MainWindow(object):
''' Handles main surface '''

    def __init__(self, width, height):
        self.WIDTH = width
        self.HEIGHT = height
        self.SURFACE = pygame.display.set_mode((width, height), 0, 32)
        pygame.display.set_caption('Placeholder')

        self.draw_rect = DrawRect(self) # <-- this line looks really strange to me

    def update(self):
        pygame.display.update()

class DrawRect(object):
''' Draw rect on the surface '''

    def __init__(self, window):
        self.window = window
        self.my_rect = pygame.Rect((50, 50), (50, 50))

    def update(self):
        pygame.draw.rect(self.window.SURFACE, (0, 0, 255), self.my_rect)

def main():
    pygame.init()

    Window = MainWindow(900, 500)
    Draw = DrawRect(Window)
    Window.draw_rect.update() # <-- this looks very missleading to me
    Window.update()

main()

According to StackOverflow question - If B want to expose the complete interface of A - Indicates Inheritance. If B want to expose only some part of A - Indicates Composition.

I don't need all of the content of the MainWindow so I use composition.

The naming conventions and specialy the line Window.draw_rect.update() in the main() function.

Later on, I will use a class Player, do I need to put something like self.player = Player(self), inside the MainWindow __init__ method? Let's say I want to use the width, height of the window to perform some method for positioning the Player.

Is there a better way to write this code, to look profesional and clear?

\$\endgroup\$
1
  • \$\begingroup\$ I suspect I'm doing a wrong object composition. \$\endgroup\$
    – dragons
    Oct 4, 2013 at 23:03

1 Answer 1

1
\$\begingroup\$

When you're composing, think about how you want to access the components you're putting together. In this example, you are asking the window to include a DrawRect that always draws to a 50 x 50 pixsel square. Does the window really need to include that rect? The DrawRect has all the info it needs -- you add the window reference in the constructor -- so what's the rationale for including it in the window? In the example code you create a DrawRect outside the window, and another inside the Window - and then never update the independent DrawRect so it never shows up. This seems less like composition and more like gluing things together which don't need to be connected.

Consider the alternative:

def main():
    pygame.init()

    Window = MainWindow(900, 500)
    ## removing the self.draw_rect field from __init__

    Rect1 = DrawRect(Window)
    Rect1.my_rect = pyGame.Rect((0,0), (50,50))

    Rect2 = DrawRect(Window)
    Rect2.my_rect = pyGame.Rect((60,60), (50,50))

    Rect1.update()
    Rect2.update()
    Window.update()

Here the DrawRects are completely independent of the Window, which seems like what you'd want.

\$\endgroup\$
4
  • \$\begingroup\$ I want to take few attributes from the Window class, but I suspect my given example is not the correct stylist way to do it, it is working, but I don't see it as a good design. I cant's seem to find a good topic to read about it. \$\endgroup\$
    – dragons
    Oct 6, 2013 at 0:09
  • \$\begingroup\$ I hit enter too early; recheck. Basically, it seems like the DrawRects and Window don't need to be connected in any way other than the need for the rect to get the surface (btw, it would be cleaner to init the DrawRects with the surface directly, since that's all they care about...) \$\endgroup\$
    – theodox
    Oct 6, 2013 at 0:11
  • \$\begingroup\$ This seems constructive but, when I instance DrawRect, I put the instance of the Window, as a prameter to the instance of DrawRect. What if I composit from multiple base classes in the DrawRect class. Then I would include all of those classes as a parameter when I instance DrawRect. Doesn't this makes the instantiation long and less readable? \$\endgroup\$
    – dragons
    Oct 6, 2013 at 0:26
  • \$\begingroup\$ You get to control the constructor of the DrawRect, so you can decide how much or how little you want to require for the constructor. In general you want to require the absolute minimum information; in the example, passing in the surface is all you'd need to do drawing and DrawRect doesn't care about, for example, the window title, or whether it's in a main window or a secondary window, etc. Always design so that class X knows as little as possible about class Y and vice-versa. Passing in the contents explicitly makes things more future proof, if slightly wordier \$\endgroup\$
    – theodox
    Oct 6, 2013 at 19:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.