Add validation and business logic to domain models

Enhance Tool, BinItem, and MultiBin classes with:
- Input validation in constructors and property setters
- Guard clauses for invalid states (negative values, empty names)
- Business logic methods (CanFitItem, CalculateWaste, etc.)
- Proper encapsulation with backing fields
- Comprehensive XML documentation
- Override Equals/GetHashCode for value semantics
- Better ToString() implementations

These changes enforce business rules at the domain level and prevent
invalid states from being created.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
AJ
2025-11-22 23:02:37 -05:00
parent f55092d877
commit d1a5dd279c
3 changed files with 303 additions and 11 deletions

View File

@@ -1,16 +1,109 @@
namespace CutList
using System;
namespace CutList
{
/// <summary>
/// Represents a cutting tool with its kerf (blade width).
/// Enforces business rules for valid tools.
/// </summary>
public class Tool
{
public string Name { get; set; }
private string _name;
private double _kerf;
public double Kerf { get; set; }
public Tool(string name, double kerf, bool allowUserToChange = false)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Tool name cannot be empty", nameof(name));
if (kerf < 0)
throw new ArgumentException("Kerf cannot be negative", nameof(kerf));
_name = name;
_kerf = kerf;
AllowUserToChange = allowUserToChange;
}
/// <summary>
/// Parameterless constructor for serialization only.
/// Use the parameterized constructor for creating valid instances.
/// </summary>
public Tool()
{
}
public string Name
{
get => _name;
set
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("Tool name cannot be empty", nameof(value));
_name = value;
}
}
public double Kerf
{
get => _kerf;
set
{
if (value < 0)
throw new ArgumentException("Kerf cannot be negative", nameof(value));
_kerf = value;
}
}
public bool AllowUserToChange { get; set; }
/// <summary>
/// Calculates the total material wasted for a given number of cuts.
/// </summary>
public double CalculateTotalWaste(int numberOfCuts)
{
if (numberOfCuts < 0)
throw new ArgumentException("Number of cuts cannot be negative", nameof(numberOfCuts));
return Kerf * numberOfCuts;
}
/// <summary>
/// Checks if this tool is compatible with the given material thickness.
/// Some tools may have minimum/maximum thickness requirements.
/// </summary>
public bool IsCompatibleWithThickness(double thickness)
{
// For now, all tools are compatible with any thickness
// This can be extended based on specific tool requirements
return thickness > 0;
}
public override string ToString()
{
return Name;
}
public override bool Equals(object obj)
{
if (obj is Tool other)
{
return Name == other.Name &&
Math.Abs(Kerf - other.Kerf) < 0.0001 &&
AllowUserToChange == other.AllowUserToChange;
}
return false;
}
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + (Name?.GetHashCode() ?? 0);
hash = hash * 23 + Kerf.GetHashCode();
hash = hash * 23 + AllowUserToChange.GetHashCode();
return hash;
}
}
}
}