Как правило, лучше избегать проверки типов. К сожалению, вы не дали достаточно контекста, как вы собираетесь использовать свои классы, чтобы я мог привести пример того, как вы можете использовать полиморфизм и избегать его.
Добавление проверки типов ограничит возможности вашей системы расти, потому что по мере добавления новых классов эти типы должны быть включены в проверки типов. Иногда это может привести к ошибкам, так как ваш код может делать предположения о количестве классов или их типов. Вот пример:
Примечание: я просто придумал это для наглядности. Дело не в том, чтобы представлять вашу логику или что-то в этом роде.
public void someMethod(Access access) {
if(access instance of InAccess) {
InAccess inAccess = (InAccess)access;
}
else {
OutAccess outAccess = (OutAccess)access;
}
}
Когда мы начинали, в нашей системе было два класса, которые наследуются от Access
. Предположим, что мы добавили еще одну Access class
в нашу систему. Этот код завершится сбоем в другом, потому что мы можем передать новый третий тип доступа, и приведение не будет успешным.
Конечно, это не всегда так. Иногда количество ваших классов не будет слишком сильно расти. Вполне возможно, что вы можете предсказать все типы, которые будут иметь.
И, конечно, поскольку все может происходить в программировании, иногда вам нужно знать типы объектов, которые вы используете.
Давайте предположим, что вашей системе нужно знать тип объектов. Вот два решения:
- Добавьте перечисление, которое будет представлять все ваши типы.
public enum AccessType {
InAccessAllowed,
InAccessDenied,
OutAccessDenied,
// other types
}
public interface Access {
AccessType getType();
// other stuff
}
Таким образом, вы будете использовать enum AccessType
вместо приведения типов.
- Использовать интерфейсы.
Вместо использования классов определите интерфейс для каждого типа Access
. Затем вы будете проверять интерфейсы вместо классов. Таким образом, ваши декораторы могут реализовать тот же интерфейс, что и класс, который он декорирует.
public interface InAllowedAccess { }
public class InAllowedAccessImp implements InAllowedAccess { }
public class InAllowedAccessDecorator implements InAllowedAccess { }
Я просто не хочу приводить пример альтернативных реализаций. Поскольку в вашем описании отсутствует контекст, я просто попытаюсь угадать, как вы собираетесь использовать свои классы, и добавить к ним поведение. Это просто идея и ничего более.
Предположим, что ваша система предоставляет доступ пользователям. Пользователям могут быть предоставлены входные и исходящие права доступа, и некоторая часть вашей системы должна спросить, разрешен ли доступ конкретному пользователю, чтобы он мог выполнять определенную логику.
Если у вас нет поведения, связанного с вашим Access classes
, вы можете просто использовать его в качестве дескриптора, который будет содержать информацию, необходимую для других классов для выполнения своей работы.
public enum PortType { In, Out }
public enum Permissions { Allowed, Denied }
public class Access {
private PortType mPortType;
private Permissions mPermissions;
public Access(PortType portType, Permissons permissions) {
mPortType = portType;
mPermissions = permissions;
}
public PortType getType() { return mPortType; }
public Permissions getPermissions() { return mPermissions; }
}
Если у вас есть поведение, то вы можете использовать полиморфизм. Определите поведение в вашем Access interface
и позвольте классам, которые управляют этим интерфейсом, определять поведение.
Допустим, у нас есть система обмена сообщениями, которая позволяет пользователю получать (входить) и отправлять (выводить) сообщения. Эти сообщения проходят через канал. Эти каналы будут либо принимать, либо отклонять сообщения. Вот способ, которым вы можете использовать полиморфизм вместо проверки типов.
public interface MessageChannel {
public bool canSendMessages(); // out
public bool canReceiveMessages(); // in
public void receiveMessage(Message m);
public void sendMessage(Message m);
}
public class InMessageChannel implements MessageChannel {
// out messaging is not allowed, cannot send
public bool canSendMessages() { return false; }
// In messaging allowed, can receive
public bool canReceiveMessages() { return true; }
public void sendMessage(Message m) {
throw new SendingMessagesIsNotAllowd();
}
public void receiveMessage(Message m); {
// do something with the mssage
}
}
public class OutMessageChannel implements MessageChannel {
// out messaging allowed
public bool canSendMessages() { return true; }
// In messaging not allowed
public bool canReceiveMessages() { return false; }
public void sendMessage(Message m) {
// send the message
}
public void receiveMessage(Message m); {
throw new ReceivingMessagesIsNotAllowd();
}
}
Как видите, с каждым MessageCahnnel
связано поведение. Он может отправлять или получать сообщения, если это разрешено или нет. Таким образом, другие классы, использующие MessageChannel
, не будут выполнять приведение типов.