2015-11-13 5 views
2

Я хочу скрыть классы специализации от внешних классов одного и того же пакета.Java + Strategy + Factory + same package = как скрыть специализированные классы?

Пример:

package com.app.letter; 
public interface LetterChange { 
    void change(); 
} 

public class A implements LetterChange{ 
    public void change(){..} 
} 

public class B implements LetterChange{ 
    public void change(){..} 
} 

Чтобы создать экземпляр этих классов я использую фабрику ....

package com.app.letter; 
public class LetterFactory{ 
    public static LetterChange getInstance(Object doesNotMatter){ 
    return doesNotMatter.isA() ? new A() : new B(); 
} 

Обратите внимание, все они находятся в одном пакете и Я НЕ ХОЧУ к поместите фабрику и специализированные классы в дополнительный пакет и измените конструкторы классов специализации на default (package).

Следуя этому примеру, у меня есть третий класс в том же пакете

package com.app.letter; 

public class DoesNotMatterClass{ 
    public void situations(){  
     LetterFactory.getInstance(null); // Legal 
     new A(); Illegal 
     new B(); Illegal  
    } 
} 

Я хочу, чтобы обеспечить A или B только заводской LetterFactory.getInstance (doesNotMatter), который находится в том же пакете.

+1

Интересно, что вы беспокоитесь о том, что классы в одном пакете совершают незаконные действия. В некотором смысле это похоже на код в классе, доступ к частным членам класса, а не через общедоступные методы. Обычно мы скрываем вещи, потому что мы не хотим, чтобы код сломался, если мы изменим их. Ожидаете ли вы, что разработчики в пакете получат доступ к A и B, не зная рисков? Кроме того, я думаю, вы могли бы сделать это с помощью модуля в Java 9, если эта функция сделает его. – Fuhrmanator

ответ

4

Сделать A и B частные статические классы завода:

public class LetterFactory{ 
    public static LetterChange getInstance(Object doesNotMatter){ 
     return doesNotMatter.isA() ? new A() : new B(); 
    } 

    private static class A implements LetterChange{ 
     public void change(){..} 
    } 

    private static class B implements LetterChange{ 
     public void change(){..} 
    } 
} 

Только завод знают о существовании этих классов и могут их создание экземпляра.

0

Вы можете скрыть A и B от других пакетов, сделав их защищенными от пакетов.

Но это не скроет их из классов в одном пакете.

Поскольку они должны быть видимыми на заводе, но не на каком-либо другом классе того же пакета, единственный способ сделать это - сделать их частными статичными вложенными классами фабричного класса.

+0

Он не хочет этого делать. Он хочет альтернативу созданию специализированного пакета. – kauedb

+0

Я никогда не предлагал создать специализированный пакет. Теперь он может захотеть создать статический вложенный класс A и B, но это единственный способ достичь цели, которую он хочет, поэтому ... –

+0

@JB Nizet. Дело в том, что я не хочу создавать A & B из тот же пакет тоже, только на Фабрике. Но спасибо за ваш ответ – Bevilaqua

2

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

Поэтому, я считаю, у вас есть не одна проблема, а два:

  1. обеспечить способ для тех, кто правильно создавать как класс A и класс B вручную, если это необходимо.
  2. Предоставьте способ создания экземпляра либо A, либо B, учитывая некоторый набор абстрактных параметров (ваше решение для Factory).

Что касается первой части, то есть 3 способа правильно создания экземпляров классов различной сложности:

  1. конструктор, который содержит список всех необходимых параметров и зависимостей. Это очень удобно использовать для простых случаев.
  2. Метод завода. Это можно использовать для более сложных сценариев.
  3. Заводской класс/класс строителя. Они обычно используются для сложных сценариев.

Теперь, какой бы вы ни выбрали, по всей логике должно быть разрешено быть общедоступным. Конструктор/фабричный метод/фабричный класс будут применять ваши правила для создания правильного действительного экземпляра либо A, либо B. И, как я уже упоминал ранее, нет возможного сценария, когда вы должны запретить создание совершенно хорошего и действительного экземпляра класса.

Предположим, вы пошли с классом строителя как наиболее сложное решение. Вот как ваш код может выглядеть:

package com.app.letter.A; 
public class A { 
    A() { //Package visibility, we don't want anyone to create an invalid A class 
     ... 
    } 
    ... 
} 

public class ABuilder { 
    public void validateAndSetSomeCriticalParam(Param param) { 
     ... 
    } 
    public A build() { 
     A a = new A(); 
     a.setSomeCriticalParam(param); 
     ... 
     return a; 
    } 
} 

Застройщик должен быть разработан в мысли в виду, что он не может каким-либо образом произвести недопустимую экземпляр A. Таким образом, вы можете позволить строителю быть единственным способом создания экземпляра A и не беспокоиться об этом, потому что все созданные им экземпляры всегда действительны. Вы можете использовать правильный API для строителя или Исключения, чтобы достичь этого. Кроме того, подход строителя является самым сложным, для некоторых более простых сценариев вы можете использовать кучу общедоступных статических методов фабрики. Однако идея должна оставаться прежней - методы общественного завода должны гарантировать, что они производят только действительные экземпляры A.

же материал для класса B, в другом пакете:

package com.app.letter.B; 
public class B { 
    ... 
} 
public class BBuilder { 
    ... 
} 

Сейчас на заводе. В принципе то же самое, что вы имели, но со строителями:

package com.app.letter; 
public class LetterFactory{ 
    public static LetterChange getInstance(Object doesNotMatter){ 
     if (doesNotMatter.isA()) { 
      ABuilder builder = new ABuilder(); 
      builder.setSomeCriticalParam(...); 
      builder... 
      return builder.build(); 
     } else { 
      BBuilder builder = new BBuilder(); 
      builder.setSomeBSpecificParam(...); 
      builder... 
      return builder.build(); 
     } 
    } 
} 

И о использований:

public class DoesNotMatterClass{ 
    public void situations(){  
     LetterFactory.getInstance(..whatever..); // Legal 
     new A(); //Illegal, as it is package protected 
     new B(); //Illegal, as it is package protected 
     new ABuilder(); //Legal, as ABuilder can ensure that only valid As are created 
     new BBuilder(); //Legal, as BBuilder can ensure that only valid Bs are created 
    } 
} 

Я добавлю, повторяюсь еще раз, вы должны скрывать только части системы, которые могут быть злоупотребляли в некотором смысле. Нет смысла скрывать класс или метод, если нет возможности злоупотреблять им. Поэтому, если вы предоставили способ правильно инициализировать действительный экземпляр A или B, вам не важно, чтобы какая-то другая часть системы могла его увидеть или использовать.

+0

Я понял ваше объяснение, и это очень полезно. Спасибо. Весь вопрос в том, что архитектурный проект моего проекта составлен так, как будто пакеты представляют ресурсы (проект веб-сервиса), и чтобы сохранить текущую архитектуру, я не хотел бы создавать пакет, чтобы применить стратегию или «гарантировать», что мой экземпляр построен правильно. Пример: com.app.user (ресурс пользователя) com.app.user.address (адресный ресурс пользователя) Если я создаю другой пакет, это означает новый ресурс (по крайней мере, сейчас). Подводя итог, чтобы сохранить это, я скорее буду следовать подходу WilQu. – Bevilaqua

+0

Преимущество, которое я вижу в сокрытии A и B (и использование фабрики), - это то же самое, что и частные члены класса: вы можете их изменить, и клиенты не будут знать, что происходит (или перерыв, если они используют их напрямую). Другими словами, любое скрытое может быть изменено без нарушения кода клиента. – Fuhrmanator

+0

@Fuhrmanator Да, и тогда вы изолируете видимые пакеты A и B в том же пакете с публичной фабрикой. Тем не менее, OP хотел добавить больше классов в этот пакет, который не смог бы получить доступ к A и B. Это, на мой взгляд, не является правильным решением, так как оно обеспечивает очень плотную связь и совпадение на уровне пакетов. Мое решение состояло в том, чтобы переделать упаковку и предоставить надлежащий публичный API. Решение, предоставленное WilQu, является противоположным - устранение публичного API и внедрение самой сильной формы связи, которая также является разумным решением в случаях, когда вы можете принести в жертву гибкость. – bezmax

 Смежные вопросы

  • Нет связанных вопросов^_^