Personnel Register
A concise architecture-first write-up of a C# personnel simulation using generic Factory Method, a JSON repository, and weekly lifecycle orchestration.
Adrian Nasrat

Introduction
This project was developed as part of a course assignment with the explicit requirement to apply the Abstract Factory Pattern in a non-trivial scenario.
The chosen theme — a simulation of ants and bees — may seem playful, but it is actually a stand‑in for a much more serious use case: designing a scalable, extensible personnel register such as a company might use to manage thousands of employees.
The architectural focus was to:
- Apply Abstract Factory to decouple construction.
- Use a Service Layer to manage lifecycles.
- Implement a generic JSON Repository for persistence instead of a full database.
The outcome is a system that demonstrates how to handle large populations with clear separation of concerns. In practice, the same architecture could manage employees in an enterprise system (with lifespans replaced by contract lengths, shifts, or employment periods).
Why Abstract Factory?
The Abstract Factory Pattern was central to the project’s design.
In the simulation it governs how ants and bees are created, but the principle applies broadly:
- Encapsulation of construction: The service layer never knows the details of how an entity is built.
- Extensibility: Adding a new type of personnel (e.g., a new insect in the demo, or a new role in a company) only requires a new class and factory.
- Consistency: All entities are created through the same interface, but internal details differ (e.g., random birthdate in the demo vs. hire date in a real system).
Generic Factory Contract
namespace PersonalRegister
{
public interface IPersonalFactory<T>
{
T Create(DateTime birthDate);
}
}
Example: Ant Factory (demo entity)
namespace PJU
{
public class AntFactory : IPersonalFactory<Ant>
{
public Ant Create(DateTime currentDate)
{
return Ant.CreateWithRandomBirthDate(currentDate);
}
}
}
In a real-world system, this might instead be an EmployeeFactory creating staff with a given hire date.
Lifecycle Orchestration
In the demo, ants live 14 days and bees live 21 days. The service removes expired entities and births slightly more than those lost, ensuring growth.
In a company system, this same pattern could model:
- Contract expiration and renewal.
- Employee attrition and hiring.
- Rotational workforce planning.
public async Task HandleWeeklyOperations(DateTime currentDate, int weekNumber)
{
var antFactory = new AntFactory();
var beeFactory = new BeeFactory();
int deadAnts = await _antRepository.RemoveDeadPersonalAsync(a => ((Ant)a).IsAlive(currentDate));
int antsToBeBorn = (int)(deadAnts * 1.1); // +10%
if (antsToBeBorn > 0)
await _antRepository.AddNewPersonalAsync(() => antFactory.Create(currentDate), antsToBeBorn);
int deadBees = await _beeRepository.RemoveDeadPersonalAsync(b => ((Bee)b).IsAlive(currentDate));
int beesToBeBorn = (int)(deadBees * 1.2); // +20%
if (beesToBeBorn > 0)
await _beeRepository.AddNewPersonalAsync(() => beeFactory.Create(currentDate), beesToBeBorn);
await SaveSimulationStateAsync(currentDate, weekNumber);
await _antRepository.SaveToFileAsync();
await _beeRepository.SaveToFileAsync();
}
Simulation Output (Console)
Continuing simulation from Week 8:
Week 9:
201673 ants died.
221840 new ants were born.
0 bees died.
Total living ants after week 9: 819648
Total living bees after week 9: 84802
Week 10:
545426 ants died.
599968 new ants were born.
40438 bees died.
48525 new bees were born.
Total living ants after week 10: 874190
Total living bees after week 10: 92889
Week 11:
673877 ants died.
741264 new ants were born.
45085 bees died.
54102 new bees were born.
Total living ants after week 11: 941577
Total living bees after week 11: 101906
Week 12:
694896 ants died.
764385 new ants were born.
49904 bees died.
59884 new bees were born.
Total living ants after week 12: 1011066
Total living bees after week 12: 111886
Simulation complete.
Process finished with exit code 0.
Interpretation: each weekly tick removes entities past their lifespan (ants ~14 days, bees ~21 days) and births slightly more than those lost (+10% ants, +20% bees). Totals show population growth across weeks.
Persisted State (JSON snapshots)
ants.json
{
"f537630ff03de4f3d92ffd2392306a5a1": {
"Id": "f537630ff03de4f3d92ffd2392306a5a1",
"BirthDate": "2025-10-17",
"HasSafetyShoes": true
},
"847a3d99f1e494eaf3959d927cce13f": {
"Id": "847a3d99f1e494eaf3959d927cce13f",
"BirthDate": "2025-10-08",
"HasSafetyShoes": true
},
"d6dc18b6cd324dd29117ed27e4e49026": {
"Id": "d6dc18b6cd324dd29117ed27e4e49026",
"BirthDate": "2025-10-18",
"HasSafetyShoes": true
}
}
bees.json
{
"de28bf373d1a49d9b0f01732fb090fbd": {
"Id": "de28bf373d1a49d9b0f01732fb090fbd",
"BirthDate": "2025-10-16"
},
"d4a8b1cdaf504359b260eb97e2ca2ebe": {
"Id": "d4a8b1cdaf504359b260eb97e2ca2ebe",
"BirthDate": "2025-10-18"
},
"3330a12159c41512bd4qabfdc557af2f": {
"Id": "3330a12159c41512bd4qabfdc557af2f",
"BirthDate": "2025-10-22"
}
}
Note: Ants include a HasSafetyShoes flag to reflect domain-specific constraints.
JSON Repository
The repository abstracts persistence. In the demo it writes JSON, but in a company setting this could connect to a database or external HR system.
public class JsonPersonalRepository<T> : IRepository<T> where T : class
{
private readonly Dictionary<string, T> _entities = new();
public async Task<int> RemoveDeadPersonalAsync(Func<T, bool> isAlive)
{
int start = _entities.Count;
var dead = _entities.Where(e => !isAlive(e.Value)).Select(e => e.Key).ToList();
foreach (var id in dead) _entities.Remove(id);
await Task.CompletedTask;
return start - _entities.Count;
}
public async Task AddNewPersonalAsync(Func<T> createNew, int count)
{
for (int i = 0; i < count; i++)
{
var entity = (dynamic)createNew();
_entities[entity.Id] = entity;
}
await Task.CompletedTask;
}
}
Process Walkthrough
- Load state from JSON at startup (in production, could be a database).
- Evaluate lifespan/contract with
IsAliverules. - Remove expired personnel (demo = dead ants/bees, real = contract ended).
- Repopulate workforce via factories.
- Save state to storage and update simulation metadata.
Conclusion
While the demo revolves around ants and bees, the architecture was deliberately designed to resemble a real personnel register.
- The Abstract Factory Pattern ensures clean extensibility of personnel types.
- The Service Layer centralizes business rules.
- The Repository abstracts persistence for flexibility.
This mirrors the same principles a company system would use to manage thousands of employees.
The exercise demonstrates not only technical correctness but also how to translate design patterns into enterprise‑ready architecture.