/> Interfacce IComparable e IComparer

Appunti di Programmazione

Interfacce IComparable e IComparer

Se creiamo un array di variabili String e volessimo riordinarli sarebbe sufficiente chiamare il metodo Array.Sort(nostro_Array) , ma se costruiamo un nuovo tipo di oggetto, e ne inseriamo una certa quantità in un array e tentassimo di usare lo stesso metodo Sort, cosa accadrebbe?

IComparable

* Avviate VB 2008 EE e selezionate un progetto console.
* Dal menù Progetto scegliete la voce "Aggiungi Classe" e nella finestra che appare digitate "Car"
* Inserite questo codice di esempio:

Public Class Car

    Private _marca As String
    Private _modello As String
    Private _tipo_auto As String

    Public Property Marca() As String
        Get
            Return _marca
        End Get
        Set(ByVal value As String)
            _marca = value
        End Set
    End Property

    Public Property Modello() As String
        Get
            Return _modello
        End Get
        Set(ByVal value As String)
            _modello = value
        End Set
    End Property

    Public Property Tipo_Auto() As String
        Get
            Return _tipo_auto
        End Get
        Set(ByVal value As String)
            _tipo_auto = value
        End Set
    End Property

    Public Sub New(ByVal marca As String, ByVal modello As String, ByVal tipo_auto As String)
        _marca = marca
        _modello = modello
        _tipo_auto = tipo_auto
    End Sub

End Class

* In "Esplora Soluzioni" selezionate Module1.vb e inserite le seguenti righe:

Module Module1

    Sub Main()

        Console.WriteLine("*****Interfaccia IComparable*****")

        Dim automobili(4) As Car
        automobili(0) = New Car("Fiat", "Bravo", "Berlina")
        automobili(1) = New Car("Ford", "Kuga", "Crossover")
        automobili(2) = New Car("Renault", "Megane GrandTour", "Station Wagon")
        automobili(3) = New Car("Chevrolet", "Matiz", "City Car")
        automobili(4) = New Car("Ferrari", "612 Scaglietti", "Sportiva")

        For Each c As Car In automobili
            Console.WriteLine("Marca: {0} Modello: {1} Tipo: {2}", c.Marca, c.Modello, c.Tipo_Auto)
        Next
        Console.ReadLine()

    End Sub

End Module

Eseguite il progetto e vedrete qualcosa di simile:

IComparable 1

Adesso aggiungete la riga in ROSSO e provate ad eseguire nuovamente il progetto.

Module Module1

    Sub Main()

        Console.WriteLine("*****Interfaccia IComparable*****")

        Dim automobili(4) As Car
        automobili(0) = New Car("Fiat", "Bravo", "Berlina")
        automobili(1) = New Car("Ford", "Kuga", "Crossover")
        automobili(2) = New Car("Renault", "Megane GrandTour", "Station Wagon")
        automobili(3) = New Car("Chevrolet", "Matiz", "City Car")
        automobili(4) = New Car("Ferrari", "612 Scaglietti", "Sportiva")


        Array.Sort(automobili)


        For Each c As Car In automobili
            Console.WriteLine("Marca: {0} Modello: {1} Tipo: {2}", c.Marca, c.Modello, c.Tipo_Auto)
        Next
        Console.ReadLine()

    End Sub

End Module

Il metodo Array.Sort funziona correttamente su i tipi semplici, come Integer e String, ma ovviamente genera un'eccezione per i tipi più complessi per i quali non è chiaro in che modo definire un qualsiasi riordinamento.
A ben pensarci non è proprio scontato che gli elementi della lista vadano ordinati rispetto alla Marca piuttosto che al Modello o al Tipo_Auto.

Per risolvere questo tipo di problematica per i nuovi tipi di dati, in questo caso la nostra classe Car, possiamo usare l'interfaccia IComparable con la quale definire una SOLA tipologia di chiave per l'organizzazione dei dati.
Per poter realizzare quanto esposto bisogna implementare l'interfaccia IComparable e scrivere il codice necessario per definire il tipo di riordinamento attraverso la definizione del metodo CompareTo(...).
Supponendo di volere organizzare i dati in base alla Marca potete aggiungere il seguente codice alla classe Car:

Public Class Car
    Implements IComparable

    Private _marca As String
    Private _modello As String
    Private _tipo_auto As String

    Public Property Marca() As String
        Get
            Return _marca
        End Get
        Set(ByVal value As String)
            _marca = value
        End Set
    End Property

    Public Property Modello() As String
        Get
            Return _modello
        End Get
        Set(ByVal value As String)
            _modello = value
        End Set
    End Property

    Public Property Tipo_Auto() As String
        Get
            Return _tipo_auto
        End Get
        Set(ByVal value As String)
            _tipo_auto = value
        End Set
    End Property

    Public Sub New(ByVal marca As String, ByVal modello As String, ByVal tipo_auto As String)
        _marca = marca
        _modello = modello
        _tipo_auto = tipo_auto
    End Sub

    Public Function CompareTo(ByVal obj As Object) As Integer Implements System.IComparable.CompareTo

        If obj Is Nothing Then Return 1
        Dim temp As Car = CType(obj, Car)
        Return String.Compare(Me._marca, temp._marca, True)

    End Function

End Class

Adesso provate ad eseguire nuovamente il progetto e vedrete che tutto funziona perfettamente: la lista dei dati viene ordinata in base alla Marca dell'auto.

IComparable 2

IComparer
Se desiderate che la lista possa essere riordinata in base a differenti criteri e non ad uno soltanto, si può utilizzare l'interfaccia IComparer.
Per poter implementare questo tipo di interfaccia è necessario creare una nuova classe che contiene la definizione del nuovo metodo di riorganizzazione della lista per ogni criterio di classificazione, usando il suo unico metodo Compare.
Volendo costruire due nuovi metodi di riordinamento su chiave Modello e Tipo_Auto bisogna fare quanto segue:

- Dal menù progetto scegliete la voce "Aggiungi Classe" e digitate il nome ModelloComparer, quindi inserite il seguente codice:

Public Class ModelloComparer
    Implements IComparer

    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer _
    Implements System.Collections.IComparer.Compare

        Dim c1 As Car = CType(x, Car)
        Dim c2 As Car = CType(y, Car)
        Return String.Compare(c1.Modello, c2.Modello)

    End Function

End Class

- Dal menù progetto scegliete la voce "Aggiungi Classe" e digitate il nome Tipo_AutoComparer, quindi inserite il seguente codice:

Public Class Tipo_AutoComparer
    Implements IComparer

    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer _
    Implements System.Collections.IComparer.Compare

        Dim c1 As Car = CType(x, Car)
        Dim c2 As Car = CType(y, Car)
        Return String.Compare(c1.Tipo_Auto, c2.Tipo_Auto)

    End Function

End Class

- A questo punto modificate Module1.vb in questo modo:

Module Module1

    Sub Main()

        Console.WriteLine("*****Interfaccia IComparable*****")

        Dim automobili(4) As Car
        automobili(0) = New Car("Fiat", "Bravo", "Berlina")
        automobili(1) = New Car("Ford", "Kuga", "Crossover")
        automobili(2) = New Car("Renault", "Megane GrandTour", "Station Wagon")
        automobili(3) = New Car("Chevrolet", "Matiz", "City Car")
        automobili(4) = New Car("Ferrari", "612 Scaglietti", "Sportiva")

        Array.Sort(automobili)

        For Each c As Car In automobili
            Console.WriteLine("Marca: {0} Modello: {1} Tipo: {2}", c.Marca, c.Modello, c.Tipo_Auto)
        Next

        Console.WriteLine()
        Console.WriteLine("*****Riordinamento per MODELLO*****")

        Array.Sort(automobili, New ModelloComparer())

        For Each c As Car In automobili
            Console.WriteLine("Marca: {0} Modello: {1} Tipo: {2}", c.Marca, c.Modello, c.Tipo_Auto)
        Next

        Console.WriteLine()
        Console.WriteLine("*****Riordinamento per Tipo_Auto*****")

        Array.Sort(automobili, New Tipo_AutoComparer())

        For Each c As Car In automobili
            Console.WriteLine("Marca: {0} Modello: {1} Tipo: {2}", c.Marca, c.Modello, c.Tipo_Auto)
        Next

        Console.ReadLine()

    End Sub

End Module

Dovreste vedere una finestra simile alla seguente:

IComparer