Это хорошая практика, чтобы использовать доступ по умолчанию для Java, чтобы скрыть классы и методы от клиента - PullRequest
4 голосов
/ 21 июля 2011
  • В случае классов:

Если мы используем фабричный метод, нам придется возвращать созданную реализацию как тип реализованного интерфейса.

public class Factory {

  public Product getProduct() {
    return new ProductA();
  }
}

public interface Product {
}

class ProductA implements Product {
}

Чтобы избежать возможности клиента преобразовать возвращенный Продукт в конкретную реализацию Продукта {A, B, C ... и т. Д.}, Мы должны:

  1. отдельно упаковывает код клиента и фабрики (скажем com.example.client и com.example.factory)
  2. объявление конкретных реализаций с доступом по умолчанию («пакет») (видимым для Factory, не видимым для Client)

    package com.example.client;
    ...
    public class Client {
      public static void main(String[] args) {
        Product i = new Factory().getProduct();
        ProductA a = (ProductA) i; // the type of ProductA isn't visible.
      }
    }
  • В случае методов:

Например, нам нужно использовать ту же фабрику со скрытым методом

public class Factory {

  public Product getProduct() {
    return new ProductA();
  }

  Product[] getCreatedProducts() {
    ...
  }
}

Я вижу здесь две проблемы:

  • плохая структура пакета: скрытые классы и методы должны быть в одном пакете с вызывающим кодом.
  • плохой код: менее интуитивно понятен и понятен. Это легко сломать, заменив java-файлы другим пакетом.

Ответы [ 4 ]

2 голосов
/ 28 июля 2011

Доступ по умолчанию не гарантирует ничего, поскольку любой мошеннический программист может объявить свой класс в вашем пакете.Кроме того, независимо от структуры вашего пакета, в Java вы почти всегда можете выполнить проверку «instance of», а затем уменьшить значение до «instance of».Таким образом, если ваша цель состоит в том, чтобы предотвратить какое-либо снижение рейтинга, вы должны использовать ключевое слово private.Например, вы можете объявить конкретные реализации вашего Product интерфейса как private static или как анонимные внутренние классы в вашем Factory.Действительно, в статье Блоха «Как разработать хороший API» он подчеркивает, что вы должны «минимизировать доступность всего».

Тем не менее, я думаю, что вы немного параноик.Неужели это так важно для тебя, если кто-то опускает руки?Любой код, который вы пишете, может быть использован не по назначению, и, конечно, если вы используете хорошо документированную фабрику, вы предоставили четкую информацию о том, как правильно использовать ваш API.Кроме того, если вы создадите настоящий фабричный метод, который принимает аргументы и имеет четкие имена методов, в отличие от этого игрушечного Factory примера, который не принимает аргументов, то я думаю, вы обнаружите, что транслируете публично значимую часть того, чтов любом случае создается.

2 голосов
/ 26 июля 2011

Я не вижу преимущества двух пакетов. Я предлагаю эту альтернативу:

    package com.example.client ;
    public interface Product
    {
         /* stuff */
    }

    package com.example.client ;
    public interface ProductFactory
    {
         Product make ( X1 x1 , X2 x2 , /* parameters */ , Xn xn ) ;
    }

    package com.example.manager;
    interface ManagedProduct extends com.example.client.Product
    {
         /* management methods */
    }

    package com.example.manager ;
    public final class DefaultProductFactory implements com.example.client.ProductFactory
    {
         public static final DefaultProductFactory instance = new DefaultProductFactory ( ) ;

         private DefaultProductFactory ( )
         {
              super ( ) ;
         }

         public ManagedProduct make ( final X1 x1 , final X2 x2 , /* parameters */ , final Xn xn )
         {
               return new ManagedProduct ( )
               {
                    /* implementation logic here */
               } ;
         }

         /*
              possibly other methods
              The Product implementation class is invisible.
          */
    }
  1. Использование двух пакетов без необходимости предоставляет класс Product реализации классу com.example.manager.DefaultProductFactory. Я бы сказал, что мой подход превосходит частный внутренний класс Bringer128 Factory . При моем подходе класс Product реализации даже невидим для других методов, которые могут существовать в классе Factory реализации.
  2. Если вы сделаете параметры окончательными, то вы можете использовать их в классе реализации продукта непосредственно из аргументов метода (не нужно (1) создавать члены X1 x1, X2 x2, ..., Xn xn; (2) this.x1 = x1, this.x2 = x2, ... и this.xn = xn в конструкторе и (3) вызывает конструктор с помощью ProductImpl (x1, x2, ..., xn). маленький, но он экономит ваши нажатия клавиш.
  3. Я полностью согласен с philwb . Это не должно рассматриваться как безопасность.
  4. Это позволяет классам в com.example.manager иметь больше методов для одного и того же объекта, чем классов в других пакетах - согласно запросу в Это хорошая практика - использовать доступ по умолчанию для Java для скрытия классов и методов от клиента .
2 голосов
/ 21 июля 2011

Я не очень понимаю, почему вы хотите поместить фабрику и классы в отдельные пакеты.

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

1 голос
/ 26 июля 2011

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

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

...