Search code examples
oopsmalltalkpharo

OO-design issue


I have a system where I have to model a household, which has a TVSubscription. This can either be a digital one, or an analog one.

A user logs into a SetTopBox. He can then rent Movies.

So the current scheme is the following:

//Existing instantiated variables in scope
aMovie
aUser
aSetTopBox
//End

--> execute this command: 
aUser rent: aVideo on: aSTB

Code:
User>>rent: aVideo on: aSTB
aVideo rentBy: self on: aSTB

Video>>rentBy: aUser on: aSTB
aUser rentActionMovie: self on: aSTB

User>> rentActionMovie: aMovie on: aSTB
aSTB rentActionMovie: aMovie by: self

STB>>rentActionMovie: aMovie by: aUser
(loggedInUser isNil)
    ifTrue: [ loggedInUser := aUser.
              --Do stuff to charge the movie]
    ifFalse: [ -- Show error that user is not logged in]

Technically speaking this is correct. But I have (Sorry for being anal) issues with this:

I have to pass aSTB 2 methods calls down to eventually use it. The double dispatch here is needed because I have Child and Adult and they can rent AdultMovie and ChildrensMovie. Therefore I use a double dispatch instead of typechecking (requirement). Therefore I thought of the following solution:

I can store currentlyLoggedIn on aSTB, and store a loggedInOn on aSTB. This however, makes the objects point to eachother.

My gut feeling tells me this is a bad smell. I'm not really sure how to fix it though.

Ideally I would like to do something like this:

aUser rent: aMovie.

Solution

  • I am no expert, but just an alternative off the top of my head...

    STB>>initialize
        aUser := UserNotLoggedIn new.
    
    STB>>rentMovie: aMovie by: aUser
        (aMovie okayFor: aUser)
            ifTrue:  [ --Do stuff to charge the movie]
    
    AdultMovie>>okayFor: aUser
        ^aUser canRentAdultMovie
    
    ChildrensMovie>>okayFor: aUser
        ^aUser canRentChildMovie
    
    User>>canRentChildMovie
        ^true
    
    User>>canRentAdultMovie
        self displayErrorCannotRentAdultMovie
        ^false
    
    Adult>>canRentAdultMovie
        ^true
    
    UserNotLoggedIn>>canRentChildMovie
        self displayErrorUserNotLoggedOn
        ^false
    
    UserNotLoggedIn>>canRentAdultMovie
        self displayErrorUserNotLoggedOn
        ^false
    
    Child "just the same as User"
    
    User>rent: aMovie.
        aSetTopBox rentMovie: aMovie by: self.
    

    aUser rent: aMovie.