OOP Areas and Volumes




The existing Model diagram.


This is an OOP Areas and Volumes Calculator. It consists of a core containing ten classes representing different geometric shapes. These shapes fall into two categories - 2D and 3D. All of the 2D Shape Classes implement the Shape2D Interface. All of the 3D Classes extend one of the 2D Classes, therefore, they indirectly implement the Shape2D Interface. Additionally, all of the 3D Classes implement the Shape3D Interface.


These are the 2D Classes


These are the 3D Classes


Implementing an Interface in a Class means that your Class must use the methods and functions stipulated in the Interface. It also means that any of the ten Core Shape Classes can be created as an Object of type Shape2D, and the seven 3D Core Shape Classes can be created as an Object of type Shape3D.


The Shape2D Interface

Public Interface Shape2D

    Function getArea() As Decimal

End Interface

The Shape3D Interface

Public Interface Shape3D

    Function getVolume() As Decimal

End Interface

The Concrete Model Classes

Circle

''' <summary>
''' 2D Circle class
''' </summary>
Public Class Circle
    Implements Shape2D

    Public Const sortIndex As Integer = 0

    Public Property Radius As Decimal

    Public Sub New(Radius As Decimal)
        Me.Radius = Radius
    End Sub

    ''' <summary>
    ''' Implemented getArea function
    ''' </summary>
    ''' <returns>Surface area of shape with specified dimensions</returns>
    Public Overridable Function getArea() As Decimal Implements Shape2D.getArea
        Return CDec(Math.PI * Me.Radius ^ 2)
    End Function

End Class

Rectangle

''' <summary>
''' 2D Rectangle class
''' </summary>
Public Class Rectangle
    Implements Shape2D

    Public Const sortIndex As Integer = 1

    Public Property Length As Decimal
    Public Property Width As Decimal

    Public Sub New(Length As Decimal, Width As Decimal)
        Me.Length = Length
        Me.Width = Width
    End Sub

    ''' <summary>
    ''' Implemented getArea function
    ''' </summary>
    ''' <returns>Surface area of shape with specified dimensions</returns>
    Public Overridable Function getArea() As Decimal Implements Shape2D.getArea
        Return Me.Length * Me.Width
    End Function

End Class

Triangle

''' <summary>
''' 2D Triangle class
''' </summary>
Public Class Triangle
    Implements Shape2D

    Public Const sortIndex As Integer = 2

    Public Property SideA As Decimal
    Public Property SideB As Decimal
    Public Property SideC As Decimal

    Public Sub New(SideA As Decimal, SideB As Decimal, SideC As Decimal)
        Me.SideA = SideA
        Me.SideB = SideB
        Me.SideC = SideC
    End Sub

    ''' <summary>
    ''' Implemented getArea function
    ''' </summary>
    ''' <returns>Surface area of shape with specified dimensions</returns>
    Public Overridable Function getArea() As Decimal Implements Shape2D.getArea
        Try
            Dim s As Decimal = CDec((Me.SideA / 2) + (Me.SideB / 2) + (Me.SideC / 2))
            Return CDec(Math.Sqrt(s * ((s - Me.SideA) * (s - Me.SideB) * (s - Me.SideC))))
        Catch ex As exception
            Return 0D
        End Try
    End Function

End Class

Cone

''' <summary>
''' 3D Cone class
''' </summary>
Public Class Cone
    Inherits Circle
    Implements Shape3D

    Public Shadows Const sortIndex As Integer = 3

    Public Property Height As Decimal

    Public Sub New(Height As Decimal, Radius As Decimal)
        MyBase.New(Radius)
        Me.Height = Height
    End Sub

    ''' <summary>
    ''' Overriden getArea function
    ''' </summary>
    ''' <returns>Surface area of shape with specified dimensions</returns>
    Public Overrides Function getArea() As Decimal
        Return CDec(Math.PI * MyBase.Radius * (MyBase.Radius + Math.Sqrt(Me.Height ^ 2 + MyBase.Radius ^ 2)))
    End Function

    ''' <summary>
    ''' Implemented getVolume function
    ''' </summary>
    ''' <returns>Volume of shape with specified dimensions</returns>
    Public Function getVolume() As Decimal Implements Shape3D.getVolume
        Return CDec((Math.PI * MyBase.Radius ^ 2 * Me.Height) / 3)
    End Function

End Class

Cylinder

''' <summary>
''' 3D Cylinder class
''' </summary>
Public Class Cylinder
    Inherits Circle
    Implements Shape3D

    Public Shadows Const sortIndex As Integer = 4

    Public Property Height As Decimal

    Public Sub New(Height As Decimal, Radius As Decimal)
        MyBase.New(Radius)
        Me.Height = Height
    End Sub

    ''' <summary>
    ''' Overriden getArea function
    ''' </summary>
    ''' <returns>Surface area of shape with specified dimensions</returns>
    Public Overrides Function getArea() As Decimal
        Return CDec(2 * Math.PI * MyBase.Radius * Me.Height + 2 * Math.PI * MyBase.Radius ^ 2)
    End Function

    ''' <summary>
    ''' Implemented getVolume function
    ''' </summary>
    ''' <returns>Volume of shape with specified dimensions</returns>
    Public Function getVolume() As Decimal Implements Shape3D.getVolume
        Return CDec(Math.PI * MyBase.Radius ^ 2 * Me.Height)
    End Function

End Class

Sphere

''' <summary>
''' 3D Sphere class
''' </summary>
Public Class Sphere
    Inherits Circle
    Implements Shape3D

    Public Shadows Const sortIndex As Integer = 5

    Public Sub New(Radius As Decimal)
        MyBase.New(Radius)
    End Sub

    ''' <summary>
    ''' Overriden getArea function
    ''' </summary>
    ''' <returns>Surface area of shape with specified dimensions</returns>
    Public Overrides Function getArea() As Decimal
        Return CDec(4 * Math.PI * MyBase.Radius ^ 2)
    End Function

    ''' <summary>
    ''' Implemented getVolume function
    ''' </summary>
    ''' <returns>Volume of shape with specified dimensions</returns>
    Public Function getVolume() As Decimal Implements Shape3D.getVolume
        Return CDec((Math.PI * MyBase.Radius ^ 3 * 4) / 3)
    End Function

End Class

Cuboid

''' <summary>
''' 3D Cuboid class
''' </summary>
Public Class Cuboid
    Inherits Rectangle
    Implements Shape3D

    Public Shadows Const sortIndex As Integer = 6

    Public Property Height As Decimal

    Public Sub New(Height As Decimal, Length As Decimal, Width As Decimal)
        MyBase.New(Length, Width)
        Me.Height = Height
    End Sub

    ''' <summary>
    ''' Overriden getArea function
    ''' </summary>
    ''' <returns>Surface area of shape with specified dimensions</returns>
    Public Overrides Function getArea() As Decimal
        Return CDec(MyBase.getArea() * 2 + MyBase.Length * Me.Height * 2 + MyBase.Width * Me.Height * 2)
    End Function

    ''' <summary>
    ''' Implemented getVolume function
    ''' </summary>
    ''' <returns>Volume of shape with specified dimensions</returns>
    Public Function getVolume() As Decimal Implements Shape3D.getVolume
        Return CDec(MyBase.getArea() * Me.Height)
    End Function


End Class

Prism

''' <summary>
''' 3D Prism class
''' </summary>
Public Class Prism
    Inherits Triangle
    Implements Shape3D

    Public Shadows Const sortIndex As Integer = 7

    Public Property Length As Decimal

    Public Sub New(Length As Decimal, SideA As Decimal, SideB As Decimal, SideC As Decimal)
        MyBase.New(SideA, SideB, SideC)
        Me.Length = Length
    End Sub

    ''' <summary>
    ''' Overriden getArea function
    ''' </summary>
    ''' <returns>Surface area of shape with specified dimensions</returns>
    Public Overrides Function getArea() As Decimal
        Return CDec(MyBase.getArea() * 2 + MyBase.SideA * Me.Length + MyBase.SideB * Me.Length + MyBase.SideC * Me.Length)
    End Function

    ''' <summary>
    ''' Implemented getVolume function
    ''' </summary>
    ''' <returns>Volume of shape with specified dimensions</returns>
    Public Function getVolume() As Decimal Implements Shape3D.getVolume
        Return CDec(MyBase.getArea() * Me.Length)
    End Function

End Class

Three_Sided_Pyramid

''' <summary>
''' 3D 3 sided Pyramid class
''' </summary>
Public Class Three_Sided_Pyramid
    Inherits Triangle
    Implements Shape3D

    Public Shadows Const sortIndex As Integer = 8
    Public Const tagNumber As Integer = 3

    Public Property Height As Decimal
    Public Property Base As Decimal

    Public Sub New(Height As Decimal, Base As Decimal, Sidelength As Decimal)
        MyBase.New(Base, Sidelength, Sidelength)
        Me.Base = Base
        Me.Height = Height
    End Sub

    ''' <summary>
    ''' Overriden getArea function
    ''' </summary>
    ''' <returns>Surface area of shape with specified dimensions</returns>
    Public Overrides Function getArea() As Decimal
        Return CDec(getBaseArea(MyBase.SideA) + MyBase.getArea() * 3)
    End Function

    ''' <summary>
    ''' Implemented getVolume function
    ''' </summary>
    ''' <returns>Volume of shape with specified dimensions</returns>
    Public Function getVolume() As Decimal Implements Shape3D.getVolume
        Return CDec((getBaseArea(MyBase.SideA) * Me.Height) / 3)
    End Function

    ''' <summary>
    ''' getBaseArea helper function
    ''' </summary>
    ''' <param name="b"></param>
    ''' <returns>3 sided pyramid base area</returns>
    Private Function getBaseArea(b As Decimal) As Decimal
        Dim s As Decimal = CDec((b * 3) / 2)
        Return CDec(Math.Sqrt(s * ((s - b) * (s - b) * (s - b))))
    End Function

End Class


Four_Sided_Pyramid

''' <summary>
''' 3D 4 sided Pyramid class
''' </summary>
Public Class Four_Sided_Pyramid
    Inherits Triangle
    Implements Shape3D

    Public Shadows Const sortIndex As Integer = 9
    Public Const tagNumber As Integer = 4

    Public Property Height As Decimal
    Public Property Base As Decimal

    Public Sub New(Height As Decimal, Base As Decimal, Sidelength As Decimal)
        MyBase.New(Base, Sidelength, Sidelength)
        Me.Base = Base
        Me.Height = Height
    End Sub

    ''' <summary>
    ''' Overriden getArea function
    ''' </summary>
    ''' <returns>Surface area of shape with specified dimensions</returns>
    Public Overrides Function getArea() As Decimal
        Return CDec(MyBase.SideA ^ 2 + 2 * MyBase.SideA * Math.Sqrt(Me.Height ^ 2 + MyBase.SideA ^ 2 / 4))
    End Function

    ''' <summary>
    ''' Implemented getVolume function
    ''' </summary>
    ''' <returns>Volume of shape with specified dimensions</returns>
    Public Function getVolume() As Decimal Implements Shape3D.getVolume
        Return CDec(((MyBase.SideA ^ 2) * Me.Height) / 3)
    End Function


End Class



The View / Controller

User input in the Form is passed to the Coordinating Class, which invokes the ClassFactory getClass function, which creates a new instance of the correct Class by substitution as an instance of Shape2D. The differences between the classes are shown as prompts in the Controller. The values used are as directed by user input. After calculating the Surface Area via the Shape2D substitution, an attempt is made to cast the instance of Shape2D to an instance of Shape3D. If the cast succeeds, a 3D shape object is selected, if the cast fails, it was a 2D shape object selected. The results of the area calculations and possibly also the volume calculations are displayed in the View Label at the bottom of the Form. The grid control used to elicit values doubles as a part of the View.

Public Class Form1

    Dim gridValues As New Dictionary(Of String, Arguments)

    ''' <summary>
    ''' Sets up the Dictionary, DGV and sets the ComboBox SelectedIndex
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        gridValues = Aggregator.getConcreteClassDetails(New String() {"Three_Sided_Pyramid", "Four_Sided_Pyramid"}, New Integer() {2, 2})
        ComboBox1.DataSource = gridValues.Keys.ToArray
        ComboBox1.SelectedIndex = 0
        DataGridView1.Columns(0).ReadOnly = True
    End Sub

    ''' <summary>
    ''' Changes the DGV prompts
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
        If ComboBox1.SelectedIndex = -1 Then Return
        DataGridView1.Rows.Clear()
        For Each s As String In gridValues(ComboBox1.Text).ArrayArgs
            DataGridView1.Rows.Add(s)
        Next
        If DataGridView1.Rows.Count < 4 Then
            DataGridView1.Rows.Add(4 - DataGridView1.Rows.Count)
        End If
        For x As Integer = 0 To DataGridView1.Rows.Count - 1
            If DataGridView1(0, x).Value Is Nothing Then
                DataGridView1(1, x).ReadOnly = True
            End If
        Next
        Label1.Text = ""
        DataGridView1.Focus()
    End Sub

    ''' <summary>
    ''' Initiates the calculation
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim cellValues(DataGridView1.Rows.Count - 1, 1) As Object
        For x As Integer = 0 To DataGridView1.Rows.Count - 1
            cellValues(x, 0) = DataGridView1(0, x).Value
            cellValues(x, 1) = DataGridView1(1, x).Value
        Next

        Label1.Text = Coordinator.getValues(ComboBox1.Text, cellValues, gridValues(ComboBox1.Text).Tag)

    End Sub

End Class


Extending the Model

To add a concrete class to the Model, a class must be added that either implements Shape2D (for a two dimensional shape), or inherits a Shape2D class and implements Shape3D. The class must implement the methods described in the relevant interface.


To add a 3D shape to the Model (in this case an Icosahedron)...

''' <summary>
''' 3D Icosahedron class
''' </summary>
Public Class Icosahedron
    Inherits Triangle
    Implements Shape3D

End Class

Add the Overridden and Implemented methods


''' <summary>
''' 3D Icosahedron class
''' </summary>
Public Class Icosahedron
    Inherits Triangle
    Implements Shape3D

    ''' <summary>
    ''' Overriden getArea function
    ''' </summary>
    ''' <returns>Surface area of shape with specified dimensions</returns>
    Public Overrides Function getArea() As Decimal

    End Function

    ''' <summary>
    ''' Implemented getVolume function
    ''' </summary>
    ''' <returns>Volume of shape with specified dimensions</returns>
    Public Function getVolume() As Decimal Implements Shape3D.getVolume
        Throw New NotImplementedException()
    End Function

End Class

Add the Constructor and a Property, and fill out the area and volume stubs


''' <summary>
''' 3D Icosahedron class
''' </summary>
Public Class Icosahedron
    Inherits Triangle
    Implements Shape3D

    Public Shadows Const sortIndex As Integer = 10
    Public Property SideLength As Decimal

    Public Sub New(SideLength As Decimal)
        MyBase.New(SideLength, SideLength, SideLength)
        Me.SideLength = SideLength
    End Sub

    ''' <summary>
    ''' Overriden getArea function
    ''' </summary>
    ''' <returns>Surface area of shape with specified dimensions</returns>
    Public Overrides Function getArea() As Decimal
        Return MyBase.getArea * 20
    End Function

    ''' <summary>
    ''' Implemented getVolume function
    ''' </summary>
    ''' <returns>Volume of shape with specified dimensions</returns>
    Public Function getVolume() As Decimal Implements Shape3D.getVolume
        Return CDec(((15 + 5 * Math.Sqrt(5)) / 12) * SideLength ^ 3)
    End Function

End Class

The Constant sortIndex is used in sorting the concrete classes. And that's all that is involved in extending the Model.


The extended Model diagram.


Taking it further

This example demonstrates OOP, Substitution, and Reflection. An OOP application uses pre-defined Objects (The Model's Concrete Shape Classes). Substitution is where you can Cast any of those concrete Shape Classes as an Object of type Shape2D, and some as Shape3D. Reflection is used on app. startup to gather information about the extensible model, then again in the ClassFactory Class to create an instance of a Class from a String name.


This example is available for download here...






Try it now...