[java] 올바른 방법보다 인터페이스에 더 많은 것이 있습니까?

따라서이 인터페이스가 있다고 가정 해 보겠습니다.

public interface IBox
{
   public void setSize(int size);
   public int getSize();
   public int getArea();
  //...and so on
}

그리고 그것을 구현하는 클래스가 있습니다.

public class Rectangle implements IBox
{
   private int size;
   //Methods here
}

인터페이스 IBox를 사용하려면 실제로 다음과 같은 방식으로 인스턴스를 만들 수 없습니다.

public static void main(String args[])
{
    Ibox myBox=new Ibox();
}

권리? 따라서 실제로이 작업을 수행해야합니다.

public static void main(String args[])
{
    Rectangle myBox=new Rectangle();
}

그것이 사실이라면, 인터페이스의 유일한 목적은 인터페이스를 구현하는 클래스가 인터페이스에 설명 된대로 올바른 메소드를 가지고 있는지 확인하는 것입니다. 아니면 다른 인터페이스 사용이 있습니까?



답변

인터페이스는 코드를보다 유연하게 만드는 방법입니다. 당신이하는 일은 이것입니다 :

Ibox myBox=new Rectangle();

그런 다음 나중에 다른 종류의 상자를 사용하려는 경우 (더 나은 종류의 상자가있는 다른 라이브러리가있을 수 있음) 코드를 다음으로 전환하십시오.

Ibox myBox=new OtherKindOfBox();

일단 익숙해지면 훌륭한 (실제로 필수적인) 작업 방법을 찾을 수 있습니다.

다른 이유는 예를 들어 상자 목록을 만들고 각 상자에 대해 일부 작업을 수행하려고하지만 목록에 다른 종류의 상자를 포함시키려는 경우입니다. 각 상자에서 다음을 수행 할 수 있습니다.

myBox.close()

(IBox에 close () 메소드가 있다고 가정) 실제 myBox 클래스는 반복중인 상자에 따라 변경됩니다.


답변

인터페이스를 유용하게 만드는 것은 “마음을 바꾸고 나중에 다른 구현을 사용할 수 있으며 개체가 생성 된 한 곳만 변경하면된다”는 사실 이 아닙니다 . 그것은 문제가 아닙니다.

실제 요점은 이미 이름입니다. 모든 사람이 해당 인터페이스에서 작동하는 모든 코드를 사용하도록 구현할 수 있는 인터페이스 를 정의합니다 . 가장 좋은 예는 다음 java.util.Collections과 같은 인터페이스에만 작동 유용한 방법 온갖 제공하는 sort()reverse()를 들어 List. 여기서 중요한 점은이 코드는 지금 정렬하거나 반대로 사용할 수 있다는 어떤 클래스가 구현하는 List인터페이스 – 단지 ArrayListLinkedList뿐만 아니라 당신이하는 방식으로 구현 될 수있는, 자신을 작성하는 것이 클래스 쓴 사람들이 java.util.Collections상상하지 않았다.

같은 방식으로 잘 알려진 인터페이스 또는 사용자가 정의한 인터페이스에서 작동하는 코드를 작성할 수 있으며 다른 사람들이 클래스를 지원하도록 요청하지 않고도 코드를 사용할 수 있습니다.

인터페이스의 또 다른 일반적인 용도는 콜백입니다. 예를 들어, java.swing.table.TableCellRenderer 는 Swing 테이블이 특정 열의 데이터를 표시하는 방법에 영향을 줄 수 있습니다. 해당 인터페이스를 구현하고 인스턴스를에 전달 JTable하면 테이블을 렌더링하는 동안 어느 시점에서 코드가 해당 작업을 수행하도록 호출됩니다.


답변

내가 읽은 많은 용도 중 하나는 Java에서 다중 상속 사용 인터페이스가 없으면 어려운 곳입니다.

class Animal
{
void walk() { }
....
.... //other methods and finally
void chew() { } //concentrate on this
} 

이제 다음과 같은 경우를 상상해보십시오.

class Reptile extends Animal
{
//reptile specific code here
} //not a problem here

그러나,

class Bird extends Animal
{
...... //other Bird specific code
} //now Birds cannot chew so this would a problem in the sense Bird classes can also call chew() method which is unwanted

더 나은 디자인은 다음과 같습니다.

class Animal
{
void walk() { }
....
.... //other methods 
} 

Animal은 chew () 메소드를 가지고 있지 않으며 대신 다음과 같은 인터페이스에 배치됩니다.

interface Chewable {
void chew();
}

그리고 파충류 클래스가 새가 아닌 이것을 구현하도록하십시오 (조류는 씹을 수 없기 때문에).

class Reptile extends Animal implements Chewable { } 

새의 경우 :

class Bird extends Animal { }


답변

인터페이스의 목적은 다형성 , 일명 유형 대체 입니다. 예를 들어 다음과 같은 방법이 있습니다.

public void scale(IBox b, int i) {
   b.setSize(b.getSize() * i);
}

scale메소드를 호출 할 때 IBox인터페이스 를 구현하는 유형의 값을 제공 할 수 있습니다. 즉, if RectangleSquareboth implement IBox이면 a Rectangle또는 Square어디에서든지 IBox기대할 수 있습니다.


답변

인터페이스는 정적으로 입력 된 언어가 다형성을 지원할 수 있도록합니다. 객체 지향적 순수 주의자는 완전한 기능을 갖춘 객체 지향 언어가되기 위해서는 언어가 상속, 캡슐화, 모듈화 및 다형성을 제공해야한다고 주장합니다. 동적 유형 또는 오리 유형 언어 (Smalltalk와 같은)에서 다형성은 사소합니다. 그러나 정적으로 유형이 지정된 언어 (예 : Java 또는 C #)에서 다형성은 사소한 것이 아닙니다 (사실상, 강력한 타이핑 개념과는 상충되는 것 같습니다).

보여 드리겠습니다 :

스몰 토크와 같이 동적으로 유형이 지정된 (또는 오리 유형의) 언어에서 모든 변수는 객체에 대한 참조입니다.

|anAnimal|
anAnimal := Pig new.
anAnimal makeNoise.

anAnimal := Cow new.
anAnimal makeNoise.

그 코드 :

  1. anAnimal이라는 지역 변수를 선언합니다 (우리는 변수의 TYPE을 지정하지 않습니다. 모든 변수는 더 이상 개체에 대한 참조입니다).
  2. “Pig”라는 클래스의 새 인스턴스를 만듭니다.
  3. 해당 Pig의 새 인스턴스를 변수 anAnimal에 지정합니다.
  4. 메시지를 보냅니다 makeNoise 를 돼지에게 .
  5. 소를 사용하여 모든 것을 반복하지만 돼지와 동일한 정확한 변수에 할당합니다.

동일한 Java 코드는 다음과 같습니다 (Duck과 Cow는 Animal의 하위 클래스라고 가정합니다).

Animal anAnimal = new Pig();
duck.makeNoise();

anAnimal = new Cow();
cow.makeNoise();

우리가 야채 클래스를 소개 할 때까지는 모두 훌륭합니다. 야채는 동물과 같은 행동을하지만 전부는 아닙니다. 예를 들어, 동물과 야채는 모두 자랄 수 있지만 분명히 야채는 소리를 내지 않으며 동물은 수확 할 수 없습니다.

스몰 토크에서는 다음과 같이 쓸 수 있습니다 :

|aFarmObject|
aFarmObject := Cow new.
aFarmObject grow.
aFarmObject makeNoise.

aFarmObject := Corn new.
aFarmObject grow.
aFarmObject harvest.

이것은 오리 유형이기 때문에 Smalltalk에서 완벽하게 작동합니다 (오리처럼 걷고, 오리처럼 qua 경우-오리입니다).이 경우 메시지가 객체로 전송되면 조회가 수행됩니다. 수신자의 메소드 목록 및 일치하는 메소드가 발견되면 호출됩니다. 그렇지 않은 경우 일종의 NoSuchMethodError 예외가 발생하지만 모두 런타임에 완료됩니다.

그러나 정적으로 유형이 지정된 언어 인 Java에서 변수에 어떤 유형을 할당 할 수 있습니까? 옥수수는 채소를 물려 받아 성장을 지원해야하지만 소리를 내지 않기 때문에 동물로부터 물려받을 수는 없습니다. 암소는 makeNoise를 지원하기 위해 동물로부터 물려 받아야하지만, 수확을 구현해서는 안되므로 야채에서는 물려받을 수 없습니다. 다중 상속이 필요한 것 같습니다 . 둘 이상의 클래스에서 상속 할 수 있습니다. 그러나 그것은 팝업이 발생하는 모든 경우 때문에 매우 어려운 언어 기능으로 판명되었습니다 (하나 이상의 병렬 수퍼 클래스가 동일한 메소드를 구현하면 어떻게됩니까? 등).

인터페이스와 함께 …

Growable을 구현할 때마다 Animal and Vegetable 클래스를 만들면 Cow는 Animal이고 Corn은 Vegetable이라고 선언 할 수 있습니다. 우리는 또한 동물과 야채 모두 성장할 수 있다고 선언 할 수 있습니다. 이를 통해 모든 것을 키울 수 있습니다.

List<Growable> list = new ArrayList<Growable>();
list.add(new Cow());
list.add(new Corn());
list.add(new Pig());

for(Growable g : list) {
   g.grow();
}

동물 소리를 내기 위해 이렇게 할 수 있습니다.

List<Animal> list = new ArrayList<Animal>();
list.add(new Cow());
list.add(new Pig());
for(Animal a : list) {
  a.makeNoise();
}

오리 유형 언어의 장점은 정말 좋은 다형성을 얻는다는 것입니다. 클래스가 행동을 제공하기 위해해야하는 모든 것은 메소드를 제공하는 것입니다. 모두가 훌륭하고 정의 된 메소드와 일치하는 메시지 만 보내는 한 모든 것이 좋습니다. 단점은 런타임까지 아래의 종류의 오류가 포착되지 않는다는 것입니다.

|aFarmObject|
aFarmObject := Corn new.
aFarmObject makeNoise. // No compiler error - not checked until runtime.

정적으로 유형이 지정된 언어는 컴파일 타임에 아래 두 가지 종류의 오류를 포착하기 때문에 “계약에 의한 프로그래밍”이 훨씬 우수합니다.

// Compiler error: Corn cannot be cast to Animal.
Animal farmObject = new Corn();
farmObject makeNoise();

// Compiler error: Animal doesn't have the harvest message.
Animal farmObject = new Cow();
farmObject.harvest(); 

요약하자면 :

  1. 인터페이스 구현을 통해 객체가 수행 할 수있는 작업 유형 (상호 작용)을 지정할 수 있으며 클래스 상속을 통해 작업 수행 방법 (구현)을 지정할 수 있습니다.

  2. 인터페이스는 컴파일러 유형 검사를 희생하지 않고 “진정한”다형성의 많은 이점을 제공합니다.


답변

일반적으로 인터페이스는 사용해야하는 인터페이스를 정의합니다 (이름에 ;-)로 표시됨). 견본


public void foo(List l) {
   ... do something
}

이제 함수 foo는 하나의 유형뿐만 아니라 ArrayLists, LinkedLists, …를 허용 합니다.

Java에서 가장 중요한 것은 여러 인터페이스를 구현할 수 있지만 ONE 클래스 만 확장 할 수 있다는 것입니다! 견본:


class Test extends Foo implements Comparable, Serializable, Formattable {
...
}

가능하지만


class Test extends Foo, Bar, Buz {
...
}

아니다!

위의 코드는 다음과 같습니다 IBox myBox = new Rectangle();.. 중요한 점은 myBox에만 IBox의 메소드 / 필드 만 포함하고의 기존 메소드는 포함하지 않는 것입니다 Rectangle.


답변

인터페이스가하는 모든 것을 이해한다고 생각하지만 인터페이스가 유용한 상황을 아직 상상하지 못하고 있습니다.

좁은 범위 내에서 (예 : 하나의 메서드 호출 내에서) 객체를 인스턴스화, 사용 및 해제하는 경우 인터페이스는 실제로 아무 것도 추가하지 않습니다. 언급했듯이 구체적인 클래스가 알려져 있습니다.

인터페이스가 유용한 곳은 오브젝트를 한 곳에서 작성하고 구현 세부 사항에 관심이없는 호출자에게 리턴해야하는 경우입니다. IBox 예제를 Shape로 변경해 봅시다. 이제 Rectangle, Circle, Triangle 등 Shape의 구현을 가질 수 있습니다. getArea () 및 getSize () 메소드의 구현은 각 구체적인 클래스마다 완전히 다릅니다.

이제 전달 된 매개 변수에 따라 적절한 모양을 반환하는 다양한 createShape (params) 메소드가있는 팩토리를 사용할 수 있습니다. 분명히 팩토리는 어떤 유형의 쉐이프가 생성되는지 알 수 있지만 호출자에게는 없습니다. 원인지 정사각형인지 걱정할 필요가 있습니다.

이제 모양에 대해 다양한 작업을 수행해야한다고 상상해보십시오. 영역별로 정렬하고 새로운 크기로 설정 한 다음 UI에 표시해야 할 수도 있습니다. 셰이프는 모두 팩토리에서 만든 다음 Sorter, Sizer 및 Display 클래스로 매우 쉽게 전달 될 수 있습니다. 나중에 육각 클래스를 추가해야 할 경우 팩토리 이외의 것을 변경할 필요가 없습니다. 인터페이스가 없으면 다른 모양을 추가하는 것은 매우 복잡한 과정이됩니다.