Reputation: 9498
I consider interfaces not only as a set of members, but also as a "contract" which force realisation to hold restrictions specified in interface documentation. For example:
interface IDevice
{
bool IsActive { get; }
int Address { get; }
/// <summary>
/// Raised when (IsActive == false)
/// and device was activated
/// </summary>
event Action Activated;
/// <summary>
/// Raised when (IsActive == true)
/// and device was deactivated
/// </summary>
event Action Deactivated;
/// <summary>
/// Raised when (IsActive == false)
/// and Address was changed
/// </summary>
event Action<int> AddressChanged;
}
Also I have users which are not interested in activation/deactivation process but want to know when Address
will change, so, lead by ISP, I create a new interface:
interface IAddressee
{
int Address { get; }
/// <summary>
/// Raised when Address was changed
/// </summary>
event Action<int> AddressChanged;
}
And now IDevice
looks like:
interface IDevice : IAddressee
{
bool IsActive { get; }
/// <summary>
/// Raised when (IsActive == false)
/// and device was activated
/// </summary>
event Action Activated;
/// <summary>
/// Raised when (IsActive == true)
/// and device was deactivated
/// </summary>
event Action Deactivated;
}
As you see, IDevice
's contract has loosed one condition: AddressChanged
event should be raised only when device is not active (IsActive == false
).
I cannot document it in IAddressee
interface since it is not depend on IDevice
and non-device implementations can exist.
Is this situation is normal? What would you do to force IDevice
realisation to correct behaviour?
I am new to the concept of contracts, so please dispel my illusions and doubts
Upvotes: 0
Views: 81
Reputation: 5790
In such cases abstract conditions will do. They express something that may depend on information not available in the top-level class. The condition is later implemented in a way suitable for a specific descendant. In your example
interface IAddressee
{
int Address { get; }
/// <summary>
/// Can Address be changed?
/// </summary>
bool IsAddessChangeable { get; };
/// <summary>
/// Raised when (IsAddessChangeable == true)
/// and Address was changed
/// </summary>
event Action<int> AddressChanged;
}
In a class that implements IDevice
, the query IsAddessChangeable
will return IsActive == false
, in other classes - the value depending on the required semantics.
Upvotes: 1