2014-12-20 6 views
5

Here Я наткнулся на этой фразе:Частные интерфейсы внутри класса

Реализация частный интерфейса является способом заставить определение методов в этом интерфейсе без добавления какой-либо информации о типе (то есть, не допуская любой взлет).

Мне трудно понять это. Может кто-нибудь объяснить это мне?

+0

Возможно, здесь уже ответил http://stackoverflow.com/questions/4573713/design-decisions-why-and-when-to-make-an-interface-private – emeraldjava

+0

@emeraldjava : Я видел этот вопрос. Но это не разъясняет эту фразу, или я не мог ее понять. Не могли бы вы указать мне соответствующий раздел или фразу? –

ответ

1

Примеры в связанной статье немного изобретательны и искусственны (как уже указывалось нечетными именами, A, B и т. Д.). Однако, давайте обратим внимание на часть цитаты, что ваш вопрос относится к:

«... без добавления каких-либо информации о типе (то есть, не допуская каких-либо приведение к базовому типу).»

Класс может предлагать несколько (публичных или частных) реализаций этого интерфейса. Но ключевым моментом является следующее:

Никто не сможет понять, что они реализуют этот интерфейс.

Просто потому, что интерфейс не является общедоступным.

Я попытался создать пример, показывающий возможный случай приложения.Конечно, это все же надуманно, но может сделать пункт более очевидным. Предположим, вы хотите смоделировать структуру данных Tree, которая состоит из Node объектов. Это могут быть объекты InnerNode (у которых есть дочерние узлы) или LeafNode объектов (у которых нет детей).

Такой класс может быть реализована следующим образом:

class Tree { 

    // The private interface 
    private interface Node { 
     List<Node> getChildren(); 
    }  

    // Both are public implementations 
    public class InnerNode implements Node { 
     @Override 
     public List<Node> getChildren() { 
      return Arrays.<Node>asList(getLeafNode(), getLeafNode()); 
     } 
    } 
    public class LeafNode implements Node { 
     @Override 
     public List<Node> getChildren() { 
      return Collections.emptyList(); 
     } 
    } 

    // These return the concrete, public types 
    public InnerNode getInnerNode() { return new InnerNode(); } 
    public LeafNode getLeafNode() { return new LeafNode(); } 

    // This returns the private interface type 
    public Node getRootNode() { 

     // Both concrete types can be returned here, 
     // because they both implement the interface 
     return getInnerNode(); // Works 
     //return getLeafNode(); // Works 
    } 

    // This uses only the interface type 
    public void traverseNode(Node node) { 
     System.out.println("Traversing "+node); 
     for (Node child : node.getChildren()) { 
      traverseNode(child); 
     } 
    } 
} 

Во внешнем main метод, вы можете наблюдать за ограничений, налагаемых частного интерфейса:

public static void main(String[] args) { 
    Tree tree = new Tree(); 

    // The public concrete types can be used 
    Tree.LeafNode leafNode = tree.getLeafNode(); 
    Tree.InnerNode innerNode = tree.getInnerNode(); 

    // The private interface can not be used from outside: 
    //Tree.Node node = tree.getRootNode(); 

    // This is possible: The class only uses its 
    // own private interface here 
    tree.traverseNode(tree.getRootNode()); 
} 

В этом примере, вы можете звоните traverseNode, передавая в Node, который возвращается getRootNode, независимо от того, является ли этот узел InnerNode или LeafNode. В текущей версии, это будет печатать что-то вроде

Traversing Tree$InnerNode 
Traversing Tree$LeafNode 
Traversing Tree$LeafNode 

Если вы изменили getRootNode вернуть LeafNode, то он будет печатать только

Traversing Tree$LeafNode 

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

0

Закрытый интерфейс - это способ заставить класс реализовать некоторые методы, не публично раскрывая, что этот интерфейс реализован - например, вы не сможете создать List<MyPrivateInterface> и добавить к нему экземпляры своего класса.

+0

Да, это правда. Но как это могло бы пояснить, что при использовании частных межфаков это позволяет нам избегать «добавления информации о типе (то есть без разрешения какого-либо повышения)». Вот что я пытаюсь понять. Благодарим вас за разъяснение. –

+1

Это просто означает, что если у вас есть 'Foo.Bar' как частный интерфейс, а объект типа' Foo.Baz реализует Foo.Bar', то код вне 'Foo' может использовать этот объект как экземпляр' Baz', но не может (вверх) передать его в «Bar». Чрезвычайно очевидное замечание. Я думаю, причина, по которой вы не понимаете этого, заключается в том, что вы ищете какой-то скрытый смысл, которого просто нет. – Dima

+0

Я думаю, он не знает, что означает повышение. – niceman

0

Я думаю, вопрос Почему вы хотите «заставить» свой собственный класс реализовать что-нибудь? Я имею в виду, что это ваш класс, если вы хотите, чтобы он реализовал метод, просто реализуйте его. «Private INTERface» - это просто неправильное название. Интерфейс - это вид вашего класса, который вы хотите выставить снаружи. Сделать его частным нецелесообразно.

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

+0

Да. Я согласен с тем, что частные интерфейсы являются своего рода «неправильным». Я просто хотел убедиться, что правильно понимаю. Может быть, мне не хватает всего смысла использовать «частные интерфейсы». –

4

Вот пример частных интерфейсов.

public class Main { 

    private interface Animal { 
     void makeNoise(); 
    } 

    public static final class Cow implements Animal { 
     @Override 
     public void makeNoise() { 
      System.out.println("Moo!"); 
     } 
    } 

    public static final class Sheep implements Animal { 
     @Override 
     public void makeNoise() { 
      System.out.println("Bah!"); 
     } 
    } 

    public static void main(String[] args) { 
     List<Animal> animals = Arrays.asList(new Cow(), new Sheep()); 
     for (Animal animal : animals) 
      animal.makeNoise(); 
    } 
}  

Изнутри класса Main вы можете обратиться к Animal и называют makeNoise() на нем. Поэтому вы можете иметь List из Animal s разных типов и использовать для каждого цикла для вызова makeNoise() на все их.

Однако вне класса Main это невозможно. Вы можете получить Cow или Sheep и позвонить по телефону makeNoise(), но интерфейс Animal и метод интерфейса makeNoise() невидимы.

+0

Спасибо за ваш пример. Хотя это «вряд ли» используется, абстракция достаточно мощная, и это уменьшает общие зависимости в дизайне и создает потенциал для повторного использования. –

+0

@tharindu_DG Я отредактировал свой ответ. Последнее предложение (теперь исключено) было вопросом мнения. –

+0

Да ..! Практически ваше мнение кажется правильным. Но не следует избегать использования частных интерфейсов. Мнения могут быть разными, обсуждения приветствуются. Спасибо за ваши мысли. –

1

Я исследовал этот номер и нашел еще информации. Ниже приведен практический пример

enter image description here

Класс SaveInterface представляет собой тип (т.е. класс, без реализации, все его методы являются абстрактными). Он имеет одну функцию открытого пользователя, называемую SaveData(). Класс Теперь из исходного решения реализуется тип SaveInterface способом, который сохраняет метод SaveData() доступным клиентам .

Обратите внимание, что в этом решении SaveHandler не имеет навигационной связи с классом Document. Это было заменено на навигационную связь с классом SaveInterface . Поскольку SaveData() объявляется публично в классе SaveInterface SaveHandler, не нужно объявлять его как друга класса Document.

Поскольку класс SaveHandler не является другом класса Document, он делает неспособным изменить какие-либо его частные переменные-члены или вызвать какие-либо из его частных функций-членов . Таким образом, инкапсуляция класса Document сохранена. Класс SaveHandler больше не нужен даже для класса Document , так как теперь он зависит от интерфейса SaveInterface. Это уменьшает общие зависимости в дизайне и создает потенциал для повторного использования.

Участники

Target (Документ)

  • определяет общий интерфейс для клиента.
  • создает объект RequestHandler (SaveHandler) и передает экземпляру RequestHandler экземпляр класса RequestInterface (SaveInterface). - в мотивирующем примере класс Document экспортирует интерфейс, который позволяет клиентам запускать асинхронные сэйвы.

Client

  • клиенты используют экспортированный интерфейс Target для выполнения конкретных функций .

Команда

  • интерфейс Command используется, потому что это, вероятно, что Target интерфейс нужно создать много различных видов RequestHandler объектов. Если все эти объекты реализуют интерфейс Command , то Factory2 может быть использован для создания отдельных объектов RequestHandler.

RequestHandler (SaveHandler)

  • создан с ссылкой на RequestInterface. реализует командный интерфейс , поэтому класс Target может вызвать функцию Execute() для выполнения запроса.

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

RequestInterface (SaveInterface)

  • определяет абстрактный интерфейс для конкретного запроса.

enter image description here

Известные применения

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

Для получения более подробной информации: http://www.objectmentor.com/resources/articles/privateInterface.pdf