Flylib.com

Books Software

 
 
 

3.9 Design Considerations

only for RuBoard

3.9 Design Considerations

Many books that cover object-oriented design do not focus on any particular language. Some don't even contain one line of code, which shows that knowledge of object design can transcend whatever language you work with.

This chapter mentions several good and not-so-good programming practices, but this discussion is only an introduction to the topic. You should remember a few general rules that will get you started on the right track:

  • Design a class from the user 's perspective, not yours. Keep it as simple as possible.

  • Limit scope as much as possible when dealing with classes, methods , and member data. Classes should expose as little as possible through their public interface. Public interfaces should have as few parameters as they can. Member data should always be Private . If it is not, think long and hard about why it isn't. Remember, changes to a class are easier to accommodate if information is hidden.

  • Classes are nouns; methods are verbs. If you find yourself writing a class named Wash , you really might be writing a method that should be in Car .

  • Methods imply behavior; properties imply state. Don't confuse the two concepts.

  • Minimize interactions among classes to reduce complexity in the system.

  • The first abstraction you come up with is probably not the best. If you get an abstraction wrong, you might end up coding yourself into a corner later on and be forced to punch holes in your once-beautiful object hierarchy.

  • Whatever you do, be consistent. A lack of consistency is a lack of style. Develop your style. The people who have to look at your code when you leave will thank you instead of curse you.

only for RuBoard
only for RuBoard

3.10 An Exercise

The chapter is "officially" over (wink, wink). The following two listings are only an exercise. Example 3-16 contains a remote debugging console. This console window can run on any computer on your network (or it can run on your only computer if you are processor-challenged). It just sits there, waiting for messages from the RemoteDebug class, which is shown in Example 3-17. To run the remote debug console, compile Example 3-16 and type the following code on the command line:

C:\>listener 1969

This line causes the remote console to wait for messages on port 1969.

Example 3-16 can be compiled from the command line as follows :

vbc /t:exe /r:system.dll listener.vb

Example 3-17 contains the listing for the RemoteDebug class, which sends messages to the remote debug console. It also contains a small test class so you can compile the class to an executable and test it. Once the remote debug console is started, you have to open up a second console window to run the executable containing the RemoteDebug class ( assuming you are testing and listening on the same machine).

Example 3-17, however, wires the remote debug class into the Log example from Example 3-9 earlier in the chapter. It can be compiled the same way as Example 3-16.

Example 3-16. Remote debug console
'references: system.dll
   
Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
   
Public Class Listener
  Implements IDisposable
   
  Private port As Integer
  Private myListener As TcpListener
  Private mySocket As Socket
  Private disposed As Boolean
   
  Public Sub New(ByVal port As Integer)
    Me.port = port
    myListener = New TcpListener(port)
  End Sub
   
  Public Sub Listen( )
   
    Dim buffer(1024) As Byte
   
    Dim bytes As Integer
    Dim ASCII As Encoding = Encoding.ASCII
   
    'Start the listener
    myListener.Start( )
   
    'Wait for a connection
    mySocket = myListener.AcceptSocket( )
   
    myListener.Stop( )
   
    'Read incoming bytes and convert to an ASCII
    'string
    bytes = mySocket.Receive(buffer, buffer.Length, 0)
   
    Do While (bytes > 0)
      Dim msg As String
      msg = ASCII.GetString(buffer, 0, bytes)
      Console.WriteLine(msg)
      bytes = mySocket.Receive(buffer, buffer.Length, 0)
    Loop
   
    mySocket.Close( )
   
  End Sub
   
  Protected Overridable Sub DoDispose( )
    mySocket.Close( )
    MyListener.Stop( )
    GC.SuppressFinalize(Me)
  End Sub
   
  Public Sub Dispose( ) Implements IDisposable.Dispose
    Dispose(True)
    GC.SuppressFinalize(Me)
  End Sub
   
  Protected Sub CheckDispose( )
    If (disposed) Then
      Throw New ObjectDisposedException( _
          "RemoteDebug has been disposed.")
    End If
  End Sub
   
  Protected Sub Dispose(ByVal disposing As Boolean)
    If Not disposed Then
      disposed = True
      If (disposing) Then
        DoDispose( )
      End If
    End If
  End Sub
   
  Public Sub Close( )
    Dispose( )
  End Sub
   
  Protected Overrides Sub Finalize( )
    Close( )
  End Sub
   
End Class
   
Public Class Application
   
  Public Shared Sub Main(ByVal args( ) As String)
    If args.Length > 1 Then
      Dim port As Integer = Convert.ToInt32(args(1))
      Console.WriteLine("Listening on port {0}", port.ToString( ))
      Dim myListener As New Listener(port)
      While (True)
        myListener.Listen( )
      End While
    Else
      Console.WriteLine("USAGE: listen <port number>")
    End If
  End Sub
   
End Class
Example 3-17. RemoteDebug class
'references: system.dll
   
Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
   
Public Class RemoteDebug
  Implements IDisposable
   
  Private remoteServer As IPAddress
  Private endPoint As IPEndPoint
  Private sock As Socket
  Private ASCII As Encoding
  Private disposed As Boolean
   
  Public Sub New(ByVal server As String, ByVal port As Integer)
    ASCII = Encoding.ASCII
    remoteServer = Dns.Resolve(server).AddressList(0)
    EndPoint = New IPEndPoint(remoteServer, port)
    'Create the Socket for sending data over TCP
    sock = New Socket(AddressFamily.InterNetwork, _
                      SocketType.Stream, _
                      ProtocolType.Tcp)
    sock.Connect(EndPoint)
  End Sub
   
  Public Sub Write(ByVal msg As String)
    CheckDispose( )
    If sock.Connected Then
      Dim buffer( ) As Byte = ASCII.GetBytes(msg)
      sock.Send(buffer, buffer.Length, 0)
    End If
  End Sub
   
  Public Sub Dispose( ) Implements IDisposable.Dispose
    Dispose(True)
    GC.SuppressFinalize(Me)
  End Sub
   
  Protected Overridable Sub DoDispose( )
    sock.Shutdown(SocketShutdown.Send)
    sock.Close( )
    GC.SuppressFinalize(Me)
  End Sub
   
  Protected Sub CheckDispose( )
    If (disposed) Then
      Throw New ObjectDisposedException( _
          "RemoteDebug has been disposed.")
    End If
  End Sub
   
  Protected Sub Dispose(ByVal disposing As Boolean)
    If Not disposed Then
      disposed = True
      If (disposing) Then
        DoDispose( )
      End If
    End If
  End Sub
   
  Public Sub Close( )
    Dispose( )
  End Sub
   
  Protected Overrides Sub Finalize( )
    Close( )
  End Sub
   
End Class
   
Public Class Test
   
  Public Shared Sub Main( )
    Dim dbg As New RemoteDebug("localhost", 1969)
    dbg.Write("This is a test")
    dbg.Close( )
  End Sub
   
End Class
only for RuBoard