If I understand your qualm with the model as-is, it's functional, but it requires that you perform run-time type-checks on an instance of IdentificationStrategy
-- and you'd like to avoid that. (Regardless of whether it's actually bad practice.) So, in light of the fact that every employee needs both, I'd suggest treating them as separate components of single Credentials
object.
You can accomplish that in one of two ways.
The more generalized, perhaps more future-looking way, I think, is to assume that a user can have N means of identification, and that they need two of any to authorize. So, for each IdentificationStrategy
object that comes in, you add it to a set of Credentials
:
public class Credentials {
public const int NumberOfDistinctIdsRequired = 2;
private List<IdentificationStrategy> ids = new List<IdentificationStrategy>();
public void AddIdentification(IdentificationStrategy id) {
if (ids.Count < NumberOfDistinctIdsRequired) {
// this .Contains() check should compare id's based on the raw, internal ID
// or hash -- NOT by the underlying user/employee.
if (!ids.Contains(id)) {
ids.Add(id);
}
}
}
public Employee AuthenticatedEmployee() {
// if we have the required number of authentication pieces,
// see whether they belong to the same employee
if (ids.Count == NumberOfDistinctIdsRequired) {
Employee rv;
for (int i = 0; i < NumberOfDistinctIdsRequired; i++) {
if (rv == null) {
rv = ids[i].getEmployee();
} else if (!rv.Equals(ids[i].getEmployee())) {
return null;
}
}
return rv;
} else {
return null;
}
}
}
Alternatively, treat one as an ID and another as a Password. I'd argue that, if the ID's are always presented in the same order, use the first-presented ID as the actual ID
and the second-presented "ID" as a Password
. In this model, your Fingerprint
and QRCode
are no longer both subclasses of IdentificationStrategy
. And whichever is treated as the Password
doesn't need to be able to return an Employee
, but is rather fetched and verified against the Employee
returned with the identifier. The identifier doesn't even need to be immediately present on the Employee
(but probably is).
Let's assume the QRCode is the ID and the fingerprint "password." So ... do something like this:
public class QRCode : Identifier {
public Employee GetEmployee() {
// return the employee stored under the GUID, Int, String, or whatever
}
}
public class Fingerprint : Password {
public bool Equals(Fingerprint p) {
// compare hashes or whatever.
}
}
public class Employee {
public Identifier Id;
private Password password;
public Boolean IsAuthenticated = false;
public Boolean Authenticate(Password p) {
if (password.Equals(p)) {
IsAuthenticated = true;
}
return IsAuthenticated;
}
}
Or offload more of the work onto the Employee
class. Or introduce a Credentials
class that treats one as an ID
and the other as a Password
. Point is, they don't both need to be treated as forms of identification if both are always present. One can be used as an identifier and the other an authenticator.
this
if you're already in theQrIdStrategy
class? – AboralidentificationStrategy
? is there anybody else who also uses the identification? like does a visitor need to identify? and is that what you want to see? is that what you want to find out? if yes then this is not the way you should do it... it looks like your problem is lack of understaning of OO. – Kliman