Получить все типы объекта Decorator: тип обернутых объектов и тип объекта-обертки - PullRequest
0 голосов
/ 01 июня 2019

Итак, это мой дизайн. Классы AccessDecorator имеют ссылку на другой Access точно так же, как обычный шаблон Decorator.

design

Но проблема в том, что когда я создаю AccessDecorator, обертывающий ConcreteAccess, а затем пытаюсь увидеть, какой тип доступа:

Access access = new InAllowedAccess();
Access wrapperAccess = new MismatchAccess(access); 
if (wrapperAccess instanceof InAllowedAccess)   //this condition could be used to be a predicate for a filtering over an access list for example
    //do something

Конечно, это не сработает, потому что wrapperAccess не относится к типу InAllowedAccess , но я действительно хочу знать, что это все типы некоторых Access. В этом случае wrapperAccess будет не только типа MismatchAccess, но и типа InAllowedAccess

Я думал о реализации таких методов, как isInstanceofInAllowed(), isInstanceofOutAllowed(), isInstanceofInDenied() и isinstanceofOutDenied(), isinstanceofMismatch() в Access классах, но не кажется хорошим решением, я не знаю ...

В противном случае я должен создать большое иерархическое дерево с MismatchAccesses для каждых 4 типов InAllowedMismatchAccess, OutAllowedMismatchAccess, InDeniedMismatchAccess и OutDeniedMismatchAccess? А потом, когда я разовью другого декоратора? ...

Или есть другой лучший дизайн?

Как я могу знать все типы Access? Не только тип доступа к оболочке, но и тип доступа к оболочке.

EDIT: Одна из моих потребностей: отфильтровать коллекцию Access es по их типу - ÌnAllowedAccess, InDeniedAccess, OutAllowedAccess, OutDeniedAccess, MismatchAccess (которая является декоратором) и другие типы декораторов, которые я может развиться

Ответы [ 2 ]

1 голос
/ 02 июня 2019

Я думал о реализации методов, таких как isInstanceofInAllowed (), isInstanceofOutAllowed (), isInstanceofInDenied () и isinstanceofOutDeniedd () в классах Access, но не кажется хорошим решением, я не знаю ...

Вы правы.Это плохое решение.Интерфейс часто относится к уровню с высоким уровнем абстракции в программном обеспечении, поэтому список его методов должен быть стабильным.Если вы поместите такую ​​кучу методов, как указано выше, в интерфейс Access, интерфейс будет очень нестабильным, поскольку в будущем очень вероятно, что вы добавите в него больше таких методов.

Самое простое решение дляВаша проблема заключается в добавлении (только один раз) нового метода с именем core() в интерфейс Access.Каждый декоратор просто реализует этот метод, возвращая обернутый / основной объект.

interface Access {
    ...
    Access core();
}

Access a = ...
if (a.core() instanceof ...
1 голос
/ 01 июня 2019

Как правило, лучше избегать проверки типов. К сожалению, вы не дали достаточно контекста, как вы собираетесь использовать свои классы, чтобы я мог привести пример того, как вы можете использовать полиморфизм и избегать его.

Добавление проверки типов ограничит возможности вашей системы расти, потому что по мере добавления новых классов эти типы должны быть включены в проверки типов. Иногда это может привести к ошибкам, так как ваш код может делать предположения о количестве классов или их типов. Вот пример:

Примечание: я просто придумал это для наглядности. Дело не в том, чтобы представлять вашу логику или что-то в этом роде.

public void someMethod(Access access) {

    if(access instance of InAccess) { 
        InAccess inAccess = (InAccess)access;
    }
    else {
        OutAccess outAccess = (OutAccess)access;
    }
}

Когда мы начинали, в нашей системе было два класса, которые наследуются от Access. Предположим, что мы добавили еще одну Access class в нашу систему. Этот код завершится сбоем в другом, потому что мы можем передать новый третий тип доступа, и приведение не будет успешным.

Конечно, это не всегда так. Иногда количество ваших классов не будет слишком сильно расти. Вполне возможно, что вы можете предсказать все типы, которые будут иметь.

И, конечно, поскольку все может происходить в программировании, иногда вам нужно знать типы объектов, которые вы используете.

Давайте предположим, что вашей системе нужно знать тип объектов. Вот два решения:

  1. Добавьте перечисление, которое будет представлять все ваши типы.

public enum AccessType { InAccessAllowed, InAccessDenied, OutAccessDenied, // other types }

public interface Access {
   AccessType getType();
   // other stuff
}

Таким образом, вы будете использовать enum AccessType вместо приведения типов.

  1. Использовать интерфейсы.

Вместо использования классов определите интерфейс для каждого типа 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, не будут выполнять приведение типов.

...