Jump to content

OOP design question


Recommended Posts

  • Replies 49
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Shouldn't the switch be connected to the light bulb? Maybe the switch should take an light bulb instance in it's constructor and save it as an property?

A switch class needs to interrupt the circuit, and as a result the light goes. If you teach the switch how to turn the light off, then the principle of least knowledge is violated. Your switch class then is not reusable if you want to add other electrical components, possibly forcing another programmer to come in and rewrite portions of your code.

Making decisions like this once is not so bad, but when you have a large project then there are going to be major problems. Therefore, it is better to do things right the first time. This all fits with object oriented fundamental principles.

According to this site: (http://www.linuxtopia.org/online_books/programming_books/thinking_in_c%2B%2B/Chapter01_002.html) a lightbulb should have four methods: on, off, dim, bright. The light can cut itself on and off and dim and brighten itself? Or deosn't it need another object to do that?

The methods on the light only indicate what a light possibly can do, not what it is doing. A different object must still come in and call those methods.

This thread makes me want to put on gauntlets and facepalm until there's nothing left.

Spare your face and enlighten us then. I still haven't mastered OO design principles after a few years of programming and I can definitely use some insights, just like everyone else here. More knowledge is better. Edited by Manadar
Link to comment
Share on other sites

If there is electricity flowing through the switch to the lightbulb then why not have an electricity object, a powerplant object, a coal object, a mine object, a power company object, and an object that goes to work to pay the bills to make sure the electricity continues to flow? Where does it all stop?

Link to comment
Share on other sites

If there is electricity flowing through the switch to the lightbulb then why not have an electricity object, a powerplant object, a coal object, a mine object, a power company object, and an object that goes to work to pay the bills to make sure the electricity continues to flow? Where does it all stop?

You try to think ahead - what would another programmer want to add? In the case of a switch being programmed so it can only be used to turn off a light you can imagine that's going to cause some problems in the future. In the case of a power company object that's also an easy choice - you don't. Don't go out of your way to make it easier to add functionality later (unless you're sure that you're going to add it), but do try not to make it harder (in the case of the switch and lightbulb dependancy).

You're right, but only some OOP principles can be used in AutoIt. And AutoIt (as mentioned) certainly isn't the best place to get an introduction into OOP.

Agreed, but I am in the dark which principles apply and which do not.
Link to comment
Share on other sites

ok, and so by putting the call to the lightbulb's onoff method in the switch's method then I have created a dependency... I, as you say, have taught the switch how to operate the lightbulb. But does that mean that electricity is necessary to create the program. Could it still be done with just a switch and a lightbulb?

Link to comment
Share on other sites

I think you need to learn more about OO design before you get too involved in the details.

You have not worked out solution yet so how can you try and implement it. Look at ER diagrams, and use cases. That will show what objects, properties and methods that are required. It looks like you are close by you have no clear design to work from.

From there the writing the code in any language will be a matter of knowing the language. Developing is not a case of just writing code.

Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]

Link to comment
Share on other sites

Circuits are dependent on each of their pieces to work, so when making a class modeling that I don't see a problem in dependency. The end result though is that the user (programmer) should be able to use the class you made without having to worry about it. Here's an example in C# of how you could have done it (ignoring technical properties of how electrical "circuits" work):

public class Circuit
        {
            private Lightbulb Light;
            private DimmerSwitch Switch;
            public Circuit(PowerConnsumer inConsumer)
            {
                Light = inConsumer as Lightbulb;
                Switch = inConsumer.PowerRegulator as DimmerSwitch;
            }
            public void On()
            {
                Light.On();
            }
            public void Off()
            {
                Light.Off();
            }
            public void Brighten()
            {
                Light.Brighten();
            }
            public void Dim()
            {
                Light.Dim();
            }
        }
        abstract public class PowerConnsumer
        {
            public WattControler PowerRegulator;
        }
        public class Lightbulb : PowerConnsumer
        {
            public DimmerSwitch PowerRegulator;
            public Lightbulb(DimmerSwitch inSwitch)
            {
                PowerRegulator = inSwitch;
            }
            public void On()
            {
                PowerRegulator.On();
            }
            public void Off()
            {
                PowerRegulator.Off();
            }
            public void Brighten()
            {
                PowerRegulator.Brighten();
            }
            public void Dim()
            {
                PowerRegulator.Dim();
            }
        }
        abstract public class WattControler
        {
            public String PowerSource;
            public int MaxWatts;
            public int CurrentWatts;
        }
        public class DimmerSwitch : WattControler
        {
            public DimmerSwitch()
            {
                PowerSource = "Local Power CO.";
                MaxWatts = 100;
                CurrentWatts = 0;
            }
            public void On()
            {
                CurrentWatts = 100;
            }
            public void Off()
            {
                CurrentWatts = 0;
            }
            public void Brighten()
            {
                CurrentWatts += 25;
                if (CurrentWatts > 100)
                    CurrentWatts = 100;
            }
            public void Dim()
            {
                CurrentWatts -= 25;
                if (CurrentWatts < 0)
                    CurrentWatts = 0;
            }
        }
        protected void Page_Load(object sender, EventArgs e)
        {
            Circuit RoomLights = new Circuit(new Lightbulb(new DimmerSwitch()));
            RoomLights.On();
        }

Above, the dependencies are simply one way, which is an arbitrary choice. I say the Circuit needs a lightbulb and the lightbulb needs a switch, but you could have set it up so that the circuit needs a switch and the switch needs a lightbulb. Either way you're just creating placeholder methods in the Circuit class to bubble the call (on,off ect) down and get it done. That way the programmer won't care how you (as the class designer) have your dependencies laid out (other than how s/he calls the constructor)... They just use RoomLights.On() and call it a day.

Link to comment
Share on other sites

bo8ster, ER diagrams are mostly for database modelling. In this case, a class diagram would be much more appropriate.

My bad, yes a class digram is what I had picured in my mind.

The interaction between the entities is important too.

Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]

Link to comment
Share on other sites

I ive begun to read the ATM Example now. Turns out I already had the thinking in c++ but I never got around to reading it! If you like puzzles then take a look at the 23 prisoners puzzle if you haven't already. See if you can turn it into an oo program.

I'd not heard of the 23 prisoners but i took up your challenge, this script is written in autoit using the AutoitObject UDF to program in a oopish way :idea:

#include <AutoItObject.au3>
_AutoItObject_Startup()

Global $oError = ObjEvent("Autoit.Error", "_myErrFunc")
Func _ErrFunc()
    ConsoleWrite("! COM Error ! Number: 0x" & Hex($oError.number, 8) & " ScriptLine: " & $oError.scriptline & " - " & $oError.windescription & @CRLF)
EndFunc   ;==>_ErrFunc

HotKeySet("{ESC}","_Exit") ; just as a safeguard

Func _Exit()
    _AutoItObject_Shutdown()
    Exit
EndFunc

; Objects used _oPrison, _oSwitch, _oSwitchRoom, _oPrisoner, _oLeadPrisoner, _oWarden

$oPrison = _oPrison()
$oPrison.EscapePlan

#region _oPrison
Func _oPrison()
    Local $oSelf = _AutoItObject_Create()
    ; _oPrison Property (variables)
    _AutoItObject_AddProperty($oSelf, "PrisonerQty", $ELSCOPE_READONLY, 23)
    _AutoItObject_AddProperty($oSelf, "SwitchRoom", $ELSCOPE_READONLY, _oSwitchRoom())
    _AutoItObject_AddProperty($oSelf, "Warden", $ELSCOPE_READONLY, _oWarden())
    ; _oPrison Method (functions)
    _AutoItObject_AddMethod($oSelf, "AddPrisoners", "_oPrison_AddPrisoners")
    _AutoItObject_AddMethod($oSelf, "MakeLeadPrisoner", "_oPrison_MakeLeadPrisoner")
    _AutoItObject_AddMethod($oSelf, "EscapePlan", "_oPrison_EscapePlan")
    $oSelf.AddPrisoners
    $oSelf.MakeLeadPrisoner($oSelf.Prisoner1)
    Return $oSelf
EndFunc   ;==>_oPrison
; _oPrison Methods
Func _oPrison_AddPrisoners($oSelf)
    For $i = 1 To $oSelf.PrisonerQty Step 1
        _AutoItObject_AddProperty($oSelf, "Prisoner" & $i, $ELSCOPE_READONLY, _oPrisoner($i))
    Next
    Return $oSelf
EndFunc   ;==>_oPrison_AddPrisoners
Func _oPrison_MakeLeadPrisoner($oSelf, $oPrisoner)
    _oLeadPrisoner($oPrisoner)
EndFunc   ;==>_oPrison_MakeLeadPrisoner
Func _oPrison_EscapePlan($oSelf)
    ConsoleWrite("Starting switch positions SwitchA = " & $oSelf.SwitchRoom.SwitchA.State & " SwitchB = " & $oSelf.SwitchRoom.SwitchB.State & @CR)
    Do
        $iChosenPrisoner = $oSelf.Warden.SelectPrisoner($oSelf.PrisonerQty)
        $sSwitch = Execute("$oSelf.Prisoner" & $iChosenPrisoner & ".MovedToSwitchRoom($oSelf.SwitchRoom.SwitchA.State, $oSelf.SwitchRoom.SwitchB.State)")
        $oSelf.SwitchRoom.FlipSwitch($sSwitch)
    Until $oSelf.Prisoner1.SwitchRoomCount = $oSelf.PrisonerQty
    ConsoleWrite(@CR)
    $iPrisonerSwitchOnCount = 0
    For $i = 1 To $oSelf.PrisonerQty Step 1
        $iTimesInSwitchRoom = Execute("$oSelf.Prisoner" & $i & ".TimesInSwitchRoom")
        $fPrisonerSwitchedOnA = Execute("$oSelf.Prisoner" & $i & ".HasSwitchedAOn")
        If $fPrisonerSwitchedOnA Then $iPrisonerSwitchOnCount += 1
        ConsoleWrite("Prisoner " & $i & " Has been in switch room " & $iTimesInSwitchRoom & " times" & " and has switch on A = " & $fPrisonerSwitchedOnA & @CR)
    Next
    $iLeadPrisonerCount = $oSelf.Prisoner1.SwitchRoomCount
    ConsoleWrite("Leader Prisoner's Count = " & $iLeadPrisonerCount & @CR)
    ConsoleWrite("Prisoner's Count = " & $iPrisonerSwitchOnCount & @CR)
    $oSelf.Warden.AllSwitchedReported($oSelf)
EndFunc   ;==>_oPrison_EscapePlan
#endregion _oPrison
#region _oSwitch
Func _oSwitch()
    Local $oSelf = _AutoItObject_Create()
    ; _oSwitch Property (variables)
    _AutoItObject_AddProperty($oSelf, "State", $ELSCOPE_READONLY, True)
    ; _oSwitch Method (functions)
    _AutoItObject_AddMethod($oSelf, "Flip", "_oSwitch_Flip")
    _AutoItObject_AddMethod($oSelf, "RandomFlip", "_oSwitch_RandomFlip")
    $oSelf.RandomFlip ; start the switch in a random state
    Return $oSelf
EndFunc   ;==>_oSwitch
; _oSwitch Methods
Func _oSwitch_Flip($oSelf)
    $oSelf.State = Not $oSelf.State
EndFunc   ;==>_oSwitch_Flip
Func _oSwitch_RandomFlip($oSelf)
    Switch Random(0, 1, 1)
        Case 0
            $oSelf.State = False
        Case 1
            $oSelf.State = True
    EndSwitch
EndFunc   ;==>_oSwitch_RandomFlip
#endregion _oSwitch
#region _oSwitchRoom
Func _oSwitchRoom()
    Local $oSelf = _AutoItObject_Create()
    ; _oSwitchRoom Property (variables)
    _AutoItObject_AddProperty($oSelf, "SwitchA", $ELSCOPE_READONLY, _oSwitch())
    _AutoItObject_AddProperty($oSelf, "SwitchB", $ELSCOPE_READONLY, _oSwitch())
    ; _oSwitchRoom Method (functions)
    _AutoItObject_AddMethod($oSelf, "FlipSwitch", "_oSwitchRoom_FlipSwitch")
    Return $oSelf
EndFunc   ;==>_oSwitchRoom
; _oSwitchRoom Methods
Func _oSwitchRoom_FlipSwitch($oSelf, $sSwitch)
    Switch $sSwitch
        Case "A"
            $oSelf.SwitchA.Flip
        Case "B"
            $oSelf.SwitchB.Flip
    EndSwitch
EndFunc   ;==>_oSwitchRoom_FlipSwitch
#endregion _oSwitchRoom
#region _oPrisoner
Func _oPrisoner($iNumber)
    Local $oSelf = _AutoItObject_Create()
    ; _oPrisoner Property (variables)
    _AutoItObject_AddProperty($oSelf, "Number", $ELSCOPE_READONLY, $iNumber)
    _AutoItObject_AddProperty($oSelf, "TimesInSwitchRoom", $ELSCOPE_READONLY, 0)
    _AutoItObject_AddProperty($oSelf, "SeenSwitchAOn", $ELSCOPE_READONLY, False)
    _AutoItObject_AddProperty($oSelf, "HasSwitchedAOn", $ELSCOPE_READONLY, False)
    ; _oPrisoner Method (functions)
    _AutoItObject_AddMethod($oSelf, "MovedToSwitchRoom", "_oPrisoner_MovedToSwitchRoom")
    Return $oSelf
EndFunc   ;==>_oPrisoner
; _oPrisoner Methods
Func _oPrisoner_MovedToSwitchRoom($oSelf, $fSwitchAPos, $fSwitchBPos)
    $oSelf.TimesInSwitchRoom = $oSelf.TimesInSwitchRoom + 1
    Local $sReturn, $sText = "I'm Prisoner " & $oSelf.Number & " i've been in the switch room " & $oSelf.TimesInSwitchRoom & " times, switchA was"
    Select
        Case $fSwitchAPos ; A is switched on
            $sText &= " On so i noted that SwitchA Has been on and flipped switchB"
            $oSelf.SeenSwitchAOn = True
            $sReturn = "B"

        Case Else
            $sText &= " Off" ; A is switched off
            Select
                Case $oSelf.HasSwitchedAOn ; i've already flipped switchA on before
                    $sText &= ", i have already flipped switchA on so i've flipped switchB instead"
                    $sReturn = "B"
                Case Else ; i've not yet flipped switchA
                    $sText &= ", i have not yet flipped switchA on"
                    Select
                        Case $oSelf.SeenSwitchAOn ; i have seen switchA on
                            $sText &= " and have seen switchA on before so i've flipped switchA on"
                            $oSelf.HasSwitchedAOn = True
                            $sReturn = "A"
                        Case Else ; i have not seen switchA on
                            $sText &= " but have not yet seen SwitchA on either, so i've flipped switchB instead"
                            $sReturn = "B"
                    EndSelect
            EndSelect
    EndSelect
    ConsoleWrite($sText & @CR)
    Return $sReturn
EndFunc   ;==>_oPrisoner_MovedToSwitchRoom
#endregion _oPrisoner
#region _oLeadPrisoner
Func _oLeadPrisoner($oPrisoner)
    $oSelf = $oPrisoner
    ; _oLeadPrisoner Property (variables)
    _AutoItObject_AddProperty($oSelf, "SwitchRoomCount", $ELSCOPE_READONLY, 0)
    _AutoItObject_AddProperty($oSelf, "LastVisitDidISwitchOn", $ELSCOPE_READONLY, False)
    ; _oLeadPrisoner Method (functions)
    _AutoItObject_AddMethod($oSelf, "MovedToSwitchRoom", "_oLeadPrisoner_MovedToSwitchRoom")
    _AutoItObject_AddMethod($oSelf, "HasAllSwitched", "_oLeadPrisoner_HasAllSwitched")
EndFunc   ;==>_oLeadPrisoner
; _oLeadPrisoner Methods
Func _oLeadPrisoner_MovedToSwitchRoom($oSelf, $fSwitchAPos, $fSwitchBPos)
    Local $sReturn, $sText = "I'm the lead Prisoner,"
    $oSelf.TimesInSwitchRoom = $oSelf.TimesInSwitchRoom + 1 ; increase times ive been in the switch room
    Select
        Case $oSelf.HasSwitchedAOn ; Been in switchroom before
            $sText &= " i've been in switch room " & $oSelf.TimesInSwitchRoom & " times, switchA was"
            Select
                Case $fSwitchAPos ; A is switched on
                    $oSelf.SwitchRoomCount = $oSelf.SwitchRoomCount + 1 ; Increase Times i think people have been in the room
                    $sText &= " On which means someone new must of been in the room so i've flipped switchA off and increased room count to " & $oSelf.SwitchRoomCount
                    $sReturn = "A"
                    $oSelf.LastVisitDidISwitchOn = False
                Case Else ; A is switched off
                    $sText &= " Off meaning no one new had been in the switch room so i've flipped SwitchB"
                    $sReturn = "B"
                    $oSelf.LastVisitDidISwitchOn = False
            EndSelect
        Case Else ; Not been in switchroom before
            $sText &= " this is my First time in switch room, switchA was"
;~          $oSelf.SwitchRoomCount = $oSelf.SwitchRoomCount + 1 ; Increase Times i think people have been in the room
            $oSelf.HasSwitchedAOn = True ; yes ive played with switchA
            Select
                Case $fSwitchAPos ; A is switched on
                    $sText &= " already on so i left SwitchA on for my go and flipped switchB"
                    $oSelf.LastVisitDidISwitchOn = True
                    $sReturn = "B"
                Case Else ; A is switched off
                    $sText &= " off so i flipped switchA on for my go"
                    $oSelf.LastVisitDidISwitchOn = True
                    $sReturn = "A"
            EndSelect
    EndSelect
    ConsoleWrite($sText & @CR)
    Return $sReturn
EndFunc   ;==>_oLeadPrisoner_MovedToSwitchRoom
Func _oLeadPrisoner_HasAllSwitched($oSelf, $iQty)
    Select
        Case Not $oSelf.SwitchRoomCount = $iQty
            Return False
        Case $oSelf.SwitchRoomCount = $iQty
            Return True
    EndSelect
EndFunc   ;==>_oLeadPrisoner_HasAllSwitched
#endregion _oLeadPrisoner
#region _oWarden
Func _oWarden()
    Local $oSelf = _AutoItObject_Create()
    ; _oWarden Property (variables)
    _AutoItObject_AddProperty($oSelf, "", $ELSCOPE_READONLY, "")
    ; _oWarden Method (functions)
    _AutoItObject_AddMethod($oSelf, "SelectPrisoner", "_oWarden_SelectPrisoner")
    _AutoItObject_AddMethod($oSelf, "AllSwitchedReported", "_oWarden_AllSwitchedReported")
    Return $oSelf
EndFunc   ;==>_oWarden
; _oWarden Methods
Func _oWarden_SelectPrisoner($oSelf, $iQty)
    Local $iPrisonerNo = Random(1, $iQty, 1)
    Return $iPrisonerNo
EndFunc   ;==>_oWarden_SelectPrisoner
Func _oWarden_AllSwitchedReported($oSelf, $oPrison)
    For $i = 1 To $oPrison.PrisonerQty Step 1
        If Execute("$oPrison.Prisoner" & $i & ".TimesInSwitchRoom") = 0 Then
            MsgBox(0, "Wrong!", "You'll all be fed to the Alligators")
            Exit
        EndIf
    Next
    MsgBox(0, "Well done!", "I will have to let you all go")
    Exit
EndFunc   ;==>_oWarden_AllSwitchedReported
#endregion _oWarden
GDIPlusDispose - A modified version of GDIPlus that auto disposes of its own objects before shutdown of the Dll using the same function Syntax as the original.EzMySql UDF - Use MySql Databases with autoit with syntax similar to SQLite UDF.
Link to comment
Share on other sites

I'd not heard of the 23 prisoners but i took up your challenge, this script is written in autoit using the AutoitObject UDF to program in a oopish way :idea:

Could the lead prisoner class inherit from the prisoner class?
Link to comment
Share on other sites

Could the lead prisoner class inherit from the prisoner class?

If he remembered to include him in his will.

:idea:

Link to comment
Share on other sites

The Lead Prisoner is just one of the prisoners Func _oLeadPrisoner($oPrisoner) that has been given his own individual version of method 'MovedToSwitchRoom' and an additional method 'HasAllSwitched' and has two extra propertys 'SwitchRoomCount' and 'LastVisitDidISwitchOn' everything else is shared with the other prisoners.

GDIPlusDispose - A modified version of GDIPlus that auto disposes of its own objects before shutdown of the Dll using the same function Syntax as the original.EzMySql UDF - Use MySql Databases with autoit with syntax similar to SQLite UDF.
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...