184 lines
No EOL
4.5 KiB
Text
184 lines
No EOL
4.5 KiB
Text
[](https://classroom.github.com/a/eADaUkhB)
|
|
:sectnums:
|
|
:nofooter:
|
|
:toc: left
|
|
:icons: font
|
|
:data-uri:
|
|
:source-highlighter: highlightjs
|
|
:stem: latexmath
|
|
|
|
= Col.05 -- Building Directory
|
|
|
|
You are going to implement a building information system.
|
|
|
|
* Situation:
|
|
** A building has multiple floors
|
|
** On each floor none, one or more companies have their offices
|
|
** Each employee of a company has an office room assigned
|
|
* We are going to support this user story:
|
|
** You received a business card from a clerk and are now on your way to visit them at their office
|
|
** Enter the building, and you find an overview:
|
|
*** Which floors exist
|
|
*** Which companies are on each floor
|
|
** Select a floor and use the elevator to get there
|
|
** Once arrived at the selected floor follow the directions, labeled with the company names, to find the reception desk of the chosen company
|
|
** Hand the business card to the reception clerk who will then tell you the room number of the person you've come to visit
|
|
** Go to the room and conduct your business
|
|
* These scenarios will be implemented with a _generic dictionary (hash map)_
|
|
|
|
[plantuml]
|
|
----
|
|
@startuml
|
|
hide empty methods
|
|
|
|
class BusinessCard {
|
|
+string FirstName [readonly]
|
|
+string LastName [readonly]
|
|
+string Department [readonly]
|
|
+string? PhoneNumber [readonly]
|
|
+string EMail [readonly]
|
|
|
|
+BusinessCard(string, string, string, string?, string)
|
|
+bool Equals(object?) [override]
|
|
+int GetHashCode() [override]
|
|
-bool Equals(BusinessCard)
|
|
}
|
|
class Company {
|
|
-MyDictionary<BusinessCard, int> _employeeRooms [readonly]
|
|
+string Name [readonly]
|
|
+int NoOfEmployees [readonly]
|
|
|
|
+Company(MyDictionary<BusinessCard, int>, string)
|
|
+int? AskForRoom(BusinessCard)
|
|
}
|
|
enum Floor {
|
|
Ground
|
|
First
|
|
Second
|
|
Third
|
|
}
|
|
class BuildingInformation {
|
|
-MyDictionary<Floor, MyDictionary<string, Company>> _companiesPerFloor
|
|
|
|
+BuildingInformation(MyDictionary<Floor, MyDictionary<string, Company>>)
|
|
+List<Floor> GetFloorSelection()
|
|
+List<string>? GetCompaniesOnFloor(Floor)
|
|
+Company? GetCompany(Floor, string)
|
|
}
|
|
class MyDictionary<TKey, TValue> {
|
|
-int InitialBuckets [const]
|
|
-int MaxDepth [const]
|
|
-List<KeyValue>[] _buckets
|
|
-int _currentMaxDepth
|
|
-int NoOfBuckets [readonly]
|
|
+int Count [private set]
|
|
+TValue? this[TKey key]
|
|
|
|
+MyDictionary()
|
|
+MyDictionary(int)
|
|
+List<TKey> GetKeys()
|
|
+List<TValue> GetValues()
|
|
+void Add(TKey, TValue)
|
|
+bool Remove(TKey)
|
|
+bool TryGetValue(TKey, out TValue?)
|
|
+bool ContainsKey(TKey)
|
|
}
|
|
|
|
Company "1" -r- "n" BusinessCard
|
|
BuildingInformation "1" -- "n" Company
|
|
BuildingInformation -r- "n" Floor
|
|
|
|
@enduml
|
|
----
|
|
|
|
== Dictionary
|
|
|
|
* Remember: a dictionary, also called a _hash map_ is similar to a hash set
|
|
** The keys are unique
|
|
** The content is unordered
|
|
* Different from a hash set, a dictionary assigns a value to each key
|
|
** Values are added _with_ and _by_ their key
|
|
** Values are retrieved by their key
|
|
* A value is not constrained
|
|
** It can occur multiple times
|
|
** It can be any object
|
|
*** Not only a single value
|
|
*** But also a collection of other values
|
|
|
|
=== Example
|
|
|
|
[cols="1,5a"]
|
|
|===
|
|
|Class |Students
|
|
|
|
|2AHIF
|
|
|
|
|
[cols="1,2"]
|
|
!===
|
|
!ID !FirstName
|
|
|
|
!IF231234
|
|
!Anna
|
|
|
|
!IF231235
|
|
!Max
|
|
|
|
!IF231236
|
|
!Linda
|
|
!===
|
|
|
|
|2BHIF
|
|
|
|
|
[cols="1,2"]
|
|
!===
|
|
!ID !FirstName
|
|
|
|
!IF234321
|
|
!Anna
|
|
|
|
!IF234322
|
|
!Anna
|
|
|
|
!IF234323
|
|
!Max
|
|
!===
|
|
|===
|
|
|
|
* `Class` & `ID` have to be _unique_ (within one dictionary)
|
|
* `Students` & `FirstName` _can_ contain the same value multiple times
|
|
|
|
=== Implementation Hint
|
|
|
|
The following _private_ members might be helpful when you implement `MyDictionary`.
|
|
|
|
[source,csharp]
|
|
----
|
|
private bool TryGetValue(TKey key, out KeyValue? existingKeyValue) [...]
|
|
private List<KeyValue> GetKeysAndValues() [...]
|
|
private void Grow() [...]
|
|
private static List<KeyValue>[] CreateBuckets(int amount) [...]
|
|
|
|
private sealed class KeyValue <1>
|
|
{
|
|
public KeyValue(TKey key, TValue value)
|
|
{
|
|
Key = key;
|
|
Value = value;
|
|
}
|
|
|
|
public TKey Key { get; }
|
|
public TValue Value { get; set; }
|
|
|
|
private bool Equals(KeyValue other) [...]
|
|
public override bool Equals(object? obj) [...]
|
|
public override int GetHashCode() [...]
|
|
}
|
|
----
|
|
<1> If implemented _within_ `MyDictionary` the type parameters `TKey` & `TValue` will be taken from the surrounding class and _don't_ have to be specified
|
|
|
|
== Tasks
|
|
|
|
As usual:
|
|
|
|
* Implement missing code pieces marked with `TODO`
|
|
* Mind the provided XMLDoc & UnitTests |