-
Notifications
You must be signed in to change notification settings - Fork 0
04 02 Base Classes
Cyberdyne Development edited this page Dec 29, 2025
·
2 revisions
Base classes define the shared properties and behavior for all type options. All properties are set via constructor parameters - never abstract properties.
From IPaymentMethod.cs:1-30:
using FractalDataWorks.Collections;
namespace Reference.TypeCollections.Basic;
/// <summary>
/// Interface for payment method type options.
/// Extends ITypeOption to enable TypeCollection discovery.
/// </summary>
/// <remarks>
/// The interface defines the contract that all payment methods must implement.
/// Each payment method knows its own processing logic - no switch statements needed!
/// </remarks>
public interface IPaymentMethod : ITypeOption<int, PaymentMethodBase>
{
/// <summary>
/// Gets the processing fee percentage for this payment method.
/// </summary>
decimal FeePercentage { get; }
/// <summary>
/// Gets a value indicating whether this method requires external authorization.
/// </summary>
bool RequiresAuthorization { get; }
/// <summary>
/// Calculates the total amount including fees.
/// Each payment method implements its own calculation logic.
/// </summary>
decimal CalculateTotal(decimal amount);
}From PaymentMethodBase.cs:1-45:
using FractalDataWorks.Collections;
namespace Reference.TypeCollections.Basic;
/// <summary>
/// Abstract base class for payment methods.
/// Inherits from TypeOptionBase for TypeCollection integration.
/// </summary>
/// <remarks>
/// The base class provides common implementation and ensures all
/// payment methods have the required TypeOption infrastructure.
/// </remarks>
public abstract class PaymentMethodBase : TypeOptionBase<int, PaymentMethodBase>, IPaymentMethod
{
/// <summary>
/// Initializes a new instance of PaymentMethodBase.
/// </summary>
/// <param name="id">Unique identifier for this payment method.</param>
/// <param name="name">Name of the payment method (must match TypeOption attribute).</param>
/// <param name="feePercentage">Processing fee percentage.</param>
/// <param name="requiresAuthorization">Whether external authorization is required.</param>
protected PaymentMethodBase(
int id,
string name,
decimal feePercentage,
bool requiresAuthorization)
: base(id, name)
{
FeePercentage = feePercentage;
RequiresAuthorization = requiresAuthorization;
}
/// <inheritdoc />
public decimal FeePercentage { get; }
/// <inheritdoc />
public bool RequiresAuthorization { get; }
/// <inheritdoc />
public virtual decimal CalculateTotal(decimal amount)
{
// Default implementation adds fee percentage
return amount * (1 + FeePercentage / 100);
}
}-
Inherit from
TypeOptionBase<TKey, TBase>- provides Id, Name, and equality -
Implement your interface - the interface extends
ITypeOption<TKey, TBase> - Constructor parameters for ALL properties - never use abstract/virtual properties
- Get-only properties (no setters) - immutable after construction
From TypeOptionBase.cs:12-88:
public abstract class TypeOptionBase<TKey, T> : ITypeOption<TKey, T>
where TKey : IEquatable<TKey>
where T : ITypeOption<TKey, T>
{
[TypeLookup("ById")]
public virtual TKey Id { get; }
[TypeLookup("ByName")]
public string Name { get; }
public string Category => string.IsNullOrEmpty(_category) ? "NotCategorized" : _category;
protected TypeOptionBase(TKey id, string name) : this(id, name, string.Empty)
{
}
protected TypeOptionBase(TKey id, string name, string? category)
{
if (name == null) throw new ArgumentNullException(nameof(name));
Id = id;
Name = name;
_category = category ?? string.Empty;
ConfigurationKey = $"TypeOptions:{name}";
DisplayName = name;
Description = $"Type option: {name}";
}
// ... equality and hash code implementations
}// WRONG: Abstract properties force each derived class to repeat the value
public abstract class PaymentMethodBase
{
public abstract decimal FeePercentage { get; } // NEVER - use constructor parameter
}
// WRONG: Virtual properties with default values encourage override chains
public virtual bool RequiresAuthorization => false; // NEVER - set via constructor- Concrete Options - Creating type options