날아라쩡글이의 블로그입니다.

추상화 본문

중앙 HTA (2106기) story/java story

추상화

날아라쩡글이 2021. 9. 24. 07:00
반응형

개발할 때 객체지향원칙의 SOLID는 중요한 원칙이다. 

개발을 쉽고, 응집도가 높게 결합도가 낮게 이뤄지게 만들어주는 원칙이다. 

위의 그림처럼 A와 B의 경우 같은 부모를 가지고 상속을 받지 않기 때문에 A와 B를 서로 전해줄 수 없다. 

  • 특징
    1. DatabaseChild와 cloudDatabaseChild의 경우 모두 Parent 타입이다. 
    2. DatabaseChild객체와 CloudDatabaseChild는 모두 Parent타입의 참조변수로 참조할 수 있다. 
      • Parent parent = new DatabaseChild();
      • Parent parent = new CloudDatabaseChild();
    3. Parent로부터 상속받은 메소드를 전부 재정의 했기 때문에 사용법이 동일하다. 
    4. DatabaseChild와 CloudDatabaseChild는 서로를 대체할 수 있다. 
  • 사용법이 동일하다는 뜻은 대체가 가능하는 뜻이다. 

다형성 발현에 필요한 필수사항

  • 소스코드의 변경없이 사용하는 객체를 교체하기 위한 필요조건 
  • 자식클래스들이 같은 부모의 클래스이며, 같은 부모의 자식이어야 한다. 
    • 부모타입의 참조변수가 모든 자식 객체를 참조할 수 없다. 
  • 자식클래스에 구현된 기능들이 (메소드들의) 사용법이 동일해야한다. 
  • 자식클래스들이 부모로부터 물려받은 기능을 메소드 재정의를 사용해서 자신에게 맞게 재정의 해야한다. 
    • 모든 자식 클래스들의 사용법이 동일해진다.
  • 사용하는 클래스에서는 부모타입의 참조변수로 필드를 정의해야 한다. UserService처럼 구현하는 클래스에서는 부모타입의 참조변수를 매개변수로, 필드로 정의해야한다. 
    • 자식객체의 종류에 상관없이 참조가 가능하다. 
  • 사용하는 클래스에서는 부모타입의 참조변수로 사용이 가능한 메소드만 사용해야한다. 
  • 사용하는 클래스에서는 생성자, Setter메소드를 통해서 필요한 객체를 제공받아야한다. 
  • Setter메소드로 정의를 하여, 전달받은 매개변수를 입력하도록 작성, 이후 출력하는 기능을 작성해야한다. 

databaseChild와 CloudDatabaseChild의 경우 1. Parent로 부터 상속을 받고 있고, 2. 서로 동일한 사용법을 가지고 있다.

UserService내용에 변화없이 사용하는 객체를 변경할 수 있다. 

  • 소스코드의 변경없이 사용하는 객체가 가능해졌다. 
    1. 확장성이 높아진다. 
    2. 유지보수가 쉬워진다. 
    3. 다형성을 발휘할 수 있다. 
  • 필요조건으로는 
    1. 같은 부모의 자식이어야 한다. 
    2. 사용방법이 동일해야한다. -->메소드의 재정의를 꼭 해야한다. 

  • OracleDatabaseAccess와 MySQLDatabaseAccess는 같은 부모의 클래스이다. 
  • OracleDatabaseAccess와 MySQLDatabaseAccesss는 사용방법이 다른 클래스이다. 
  • OracleDatabaseAccess나 MySQLDatabaseAccess는 서로를 대체할 수 없다. 

 

parent의 참조 변수로 OracleDatabaseAccess의 기능을 실행할 수 없다. 만약 사용하고 싶다면? 강제 형변환만이 사용할 방법!!! 

parent의 참조 변수로 MySQLDatabaseAccess의 메소드가 사용되었다. 강제형변환없이 재정의 메소드 실행이 가능하다. 

사용법이 똑같아지게 만들어주는 것...!! 그게 바로 

추상화 

이다.

추상화(Abstraction) 

  • 추상화는 객체에서 공통된 속성와 기능을 추출하는 것이다. 
  • 자바에서 추상화는 공통된 속성과 기능을 모아서 추상클래스 (Abstract Class)나 인터페이스(Interface)를 정의하는 것이다. 
  • 공통 속성은 변수나 상수로 표현하고 기능은 추상메소드로 표현한다. 
  • 추상화를 통해서 하위 클래스들이 구현해야할 공통기능을 정의할 수 있다. 

추상메소드 

  • 추상메소드는 공통기능을 추상화하는 메소드이다. 
  • 추상메소드는 구현부가 없는 메소드이다. 
  • 추상메소드는 추상클래스와 인터페이스에만 정의할 수 잇다. 
  • 일반클래스 (구현하는 클래스 )는 추상메소드를 보유할 수 없다. (구현부가 없기 때문에, 생성자 메소드랑 다른이야기이다.)
  • 만약, 추상메소드를 상속받았다면 반드시 메소드 재정의를 통해서 구현부가 있는 메소드로 만들어야한다. 
  • abstract의 경우 Body가 없이 선언부만 존재한다고 생각하면 된다.

인터페이스 (Interface)

  • 인터페이스는 하위 클래스에 특정한 메소드가 반드시 존재하도록 강제할 때 사용된다. 
  • 인터페이스는 모든 하위클래스의 사용법(메소드의 실행방법)을 통일시키는 표준으로 사용된다. 
  • 하위클래스는 인터페이스에 정의된 추상화된 메소드를 구현(재정의)할 책임이 있다. 
  • 하위클래스는 동시에 여러개의 인터페이스를 구현할 수 있다. 

interface의 경우 자바 8 이전과 이후로 문법상으로 바뀐부분이 있다. 

클래스와 인터페이스 (자바 8이전 문법의 기준)

  • 클래스 (class) 
    1. 멤버변수, 클래스 변수, 생성자, 멤버메소드, 클래스 메소드를 보유할 수 있다(필드, static변수-클래스저장공간에서 관리하는 변수, 클래스 name과 동일하고, overLoding하는 생성자, 메소드, static메소드-클래스저장공간에서 관리하는 메소드)
    2. new연산자를 사용해서 객체를 생성할 수 있다. 
    3. 단일 상속만 지원한다. 
    4. 객체 생성에 설계되는 설계도 이다. 
      1. 객체의 속성(성질, 고유한 값)을 저장하는 변수가 있다. 
      2. 객체의 기능이 구현된 메소드가 있다. 
      3. 객체의 초기화를 담당하는 생성자 메소드가 있다.
  • 인터페이스 (interface)
    1. 상수, 추상메소드만 보유할 수 있다. 
      • 추상메소드는 구현부가 없는 메소드이다. 
      • 상수의 경우 인터페이스는 필수로 정의해야하는 메소드를 가지고 있기 때문에 값이 변하지 않기 위해서 public static FINAL 의 형태의 상수를 필드로 가지고 있다. 
    2. 객체를 생성할 수 없다. 
    3. 다중상속을 지원한다. --->부모가 2개여도 된다. 
    4. 구현클래스가 반드시 구현할 기능을 정의하는 표준(스펙)이다. -->인터페이스는 표준안이다. 빈껍데기이다. 
      • 구현클래스가 재정의 할 기능에 대한 명세서다. 
      • 구현부가 없는 추상메소드는 구현클래스가 재정의 할 기능에 대한 명세서이다. 

구현클래스와 인터페이스 

  1. 구현클래스는 하나이상의 인터페이스를 구현한 클래스다. 
  2. 구현클래스는 구현부가 없는 추상메소드를 포함할 수 없다.
    • 만약 구현부가 없는 메소드를 상속받으면 무조건!!!!!!!!!!!!!!!!!!!!!!!!!!재정의해야한다. 
  3. 구현클래스는 인터페이스에 정의된 구현부가 없는 메소드를 전부!!재정의한 클래스이다. 
    • 구현클래스에는 구현부가 없는 메소드가 하나도 없다. 
  4. 구현클래스에는 implements 키워드를 사용해서 자신이 구현할 기능이 선언되어 있는 인터페이스들을 지정할 수 있다. 
    • public class 구현클래스 implements 인터페이스1, 인터페이스2,...., 인터페이스 N{
      •    1. 각 인터페이스에 정의된 구현부가 없는 추상메소드를 전부 재정의한다. 
      •    2. 구현부가 없는 추상메소드가 하나라도 재정의 되지 않으면 구현 클래스는 컴파일 오류가 발생된다. 
    • }
  5. 구현클래스는 지금까지 배운 것이 구현클래스이다. 인터페이스와 연관하여 생각하면 된다. 
  6. 인터페이스의 추상화 클래스를 구체화 시킨 클래스이다. 
  7. 따라서, 특정인터페이스를 구현한 구현클래스들은 언제나 동일한 구현 메소드를 가지고 있다. 즉, 인터페이스를 상속한 구현클래스는 인터페이스의 타입의 부모를 가지고 있다고 생각하면 된다. 부모 = 인터페이스 
  8. 인터페이스 내부에 추상메소드가 2개가 있다면 무조건 2개를 구현해야한다. 

부모는 클래스와 인터페이스로 가질 수 있다. 

차이점

인터페이스 설정하기 

  • 차는 출발, 정지, 속도변경, 속도조회 기능이 있어야한다. 
  • 인터페이스는 전부 추상메소드이기 때문에 public abstract 를 생략할 수 있다. 
  • public abstract void start();//이게 추상메소드, 출발
    public abstract void stop();//정지
    /*public abstract*/ void speedUp(); //스피드 올림
    public abstract void speedDown(); //스피드내림
    public abstract int getCurrentSpeed(); //현재속도조회
  • 구현부가 없는 추상메소드를 정의하기 
    • 추상메소드는 구현부가 없는 메소드이다. 
    • 추상메소드는 abstract키워드를 포함해야한다. 
    • 인터페이스에서는 public abstract를 생략할 수 있다. 
    • 이 인터페이스를 구현하는 구현클래스가 반드시 재정의할 기능을 추상메소드로 정의한다. 
  • impements 는 구현하다, 구체화 하다의 의미를 갖는다 
  • 모든 자동차의 속도는 최저 0미만의 속도가 나올 수 없고, 200키로 이상의 속도가 나올 수 없다. 
  • /*public static final */int MIN_SPEED = 0;
    public static final int MAX_SPEED = 200;
  • 이렇게 상수로 지정해줄 예정이다. 
  • 상수정의하기 
    • 상수는 변하지 않는 값의 저장소이다. 
    • 상수는 public static final키워드를 포함한다. 
    • 상수의 이름은 전부 대문자로 쓰고, 두단어 이상일 때는 중간에 _를 삽입한다. 
    • 인터페이스에서는 public static Final를 생략할 수 있다. 
    • public 공개되있는 static공통의 클래식 변수 Final 상수이다. 
  • 강제하기 때문에 
  • 인터페이스의 경우 
    • 강제하기 때문에 구현클래스의 표준(스펙) 이 된다. 
    • 구현클래스가 구현할 기능을 지정한다. 
    • 구현클래스들의 사용법이 똑같아 지도록 하는 것이 목적이다. 

위의 그림을 확인해보면 집을 만드는 사람은 어떤 창문을 사용할 지 모르는 상태에서 창문의 부모를 작성하고 구현해냈다. 즉, 이 집에서는 window 인터페이스를 구현한 객체만 사용할 것이다라는 의미로 사용할 수 있다.(표준사용) window를 만드는 사람은 window의 종류만 중요하고 어떤집에 놓을 것인지는 중요하지 않다. 즉, 우리는 window인터페이스를 구현한 객체만 생성한다는 의미로 볼 수 있다. (표준생산) 전체적으로 표준안을 둔 상태로 구현해낸것을 확인 할 수 있다.

참조변수로 사용할 수 있는 것

  • 부모클래스타입의 참조변수는 자식객체를 참조할 수 있다. 
    • ParentClass parent = new Child();
  • 부모인터페이스는 자식객체를 참조할 수 있다. 
    • ParentInterface parent = new Child();
  • 생성된 객체와 같은 타입의 참조변수는 객체를 참조할 수 있다.
    • Child child = new Child();
  • Object 타입의 참조변수는 자식객체를 참조할 수 있다. 
    • Object topParent = new Child();
  • 즉, 자식객체를 참조할 수 있는 참조변수는?? 나 자신, 부모 클래스, 부모 인터페이스, 최고조상인 Object라는 것을 알 수 있다. 
  • Child 클래스는 parent  class를 상속받았다, parent interface를 구현했다 -> 상속과 구현이 가능하다.
    • public class child extends parentClass implements ParentInterface

인터페이스타입의 정의 구현

  • 클래스를 만들 수 있다. 
  • 목적 : 반드시 메소드의 전체를 구현하기 위해서 작성함
  • 좋은 점 : 사용방법이 같은 객체를 여럿 만들 수 있다. 

Company의 경우 Report와 의존관계로 Report를 멤버변수로 작성하였고, 멤버변수의 메소드를 원한다. 정의하고displayCompanyEarning()으로 출력하기위해서 Report가 어뎁터의 역활을 했다고 생각하면 된다. 

Report를 구현해놓은 메소드를 출력해서 사용이 가능하다. 상속관계에 있는 ExcelReporter의 경우 Report의 표준안인 printReport();를 메소드를 재정의 하고 있기 때문에 출력이 가능해지기 때문이다. 

인터페이스는 구현객체들과 구현클래스객체만 사용이 가능하다.

어뎁터

  1. 구현 클래스에 멤버변수에 어뎁터를 설정한다. 
  2. 객체 전달받은 setter메소드를 작성한다. 
  3. 영업이익과 레포트를 출력하는 기능메소드를 입력한다. 
  4. PrintRepoprt의 기능을 실행한다. 
  5. 메인메소드
    1. 영업이익의 데이터를 작성한다. 
    2. Reporter 인터페이스의 구현 객체를 생성한다. 
    3. Company객체 멤버변수(인터페이스)구현한 setter메소드에 입력하여 연결해준다. 본체의 어뎁터부분을 연결해준다고 생각하면 된다. setter을 이용하여 멤버변수로 참조변수의 주소값을 전달해 준다. 

메인메소드 작성 하기

메인메소드로 서로 연관지어서 출력할 수 있다. 

  1. 구현메소드를 new 연산자를 이용하여 참조변수에 주소값을 입력한다. 
  2. 의존관계로 인터페이스를 매개변수로 입력한 클래스를 참조주소값에 주소값을 new연산자로 작성한다. 
  3. 서로 아무런 연관관계가 없지만 report라는 관계로 인하여 연결이 되었다!!
  4. 의존관계 클래스의 setter메소드에 구현클래스의 참조변수를 입력하여 매개변수로 주소값이 입력이 될 수 있게 작성한다. 
  5. 그리고 의존관계의 메소드를 출력했을 때 매개변수의 있는 주소값의 매소드 재정의 된 메소드가 출력이 가능하다.

느슨한 결합

  • Company는 Reporter의 인터페이스의 구현객체를 필요로 한다. 
  • Company는 구체적인 클래스의 이름은 알지 못한다. 
  • Compant는 자신에게 전달된 Reporter의 구현객체를 사용할 뿐이다.
  • 즉, Company는 자신에게 전달된 Reporeter 구현객체의 구체적인 존재는 알지 못하지만, 구현객체에 재정의된 메소드를 실행하는데는 아무 문제가 없다.
  • Company와 Reporter 구현객체의 결합은 결합도가 낮은 결합이다.
  • 결합도가 낮은 결합은 쉽게 다른 객체로 교체할 수 있다.
  • 인터페이스는 클래스 간의 결합을 느슨하게 만든다. 

인터페이스의 사용이유

  • 같은 사용 방법을 사용하기 위해서 
  • 객체간의 느슨한 결합을 사용하기 위해서 
  • 응집력이 높고 결합도가 떨어지는 것이 좋은 것이다. 
  • 주소값의 경우 C/C++의는 포인터로 중요하지만 java는 객체가 바라보는데 활용될 뿐임

A회사의 경우 

  • Company.java   //변경없음
  • Reporter.java //변경없음
  • ExcelReporter.java //엑셀리포트 제공
  • CompanyApp.java // 실행프로그램

B회사의 경우

  • Company.java  //변경없음
  • Reporter.java // 변경없음
  • ChartReporter.java //차트레포트 제공
  • CompanyApp2.java // 실행프로그램 

엑셀레포트와 차트레포트를 함께 제공할 수는 없다 단일책임의 원칙에 위배가 된다. 

C회사에서는 지도레포트로 원할경우 --> 3번째에 입력되는 레포트를 지도형태로 변경하여 추가하면 된다. 

Company는 Reporter만 보고 작성을 한다. Reporter라는 인터페이스를 보고 준수하여 개발했기 때문에 서로 같은 표준안을 보고 만든 것 끼리 결합이 가능하다.

Company개발자 

  • Reporter인터페이스타입의 참조변수를 정의한다.
    •  Reporter인터페이스를 구현한 객체가 조립될 수 있게 된다.
  • Reporter인터페이스에 정의된 기능을 사용해서 업무로직을 구현한다. 
    • Reporter 인터페이스를 구현한 객체는 전부 Reporter 인터페이스에 정의된 기능을 전부 구현하고 있기 때문에, 조립된 구현객체가 변경되어도 업무로직의 소스를 변경할 필요가 없다.(거기에 있는 기능만 사용할테니까)
  • Company개발자가 Reporter인터페이스에 맞춰서 Company를 개발했다. 
    • Company는 Reporter인터페이스를 구현한 구체적인 구현클래스의 이름은 알지 못한다. 
    • Company는 Reporter인터페이스를 구현한 어떤 구현객체와도 조립이 가능하다 (구현클래스의 이름은 모르고 단지 표준안타입의 인터페이스라면 괜찮음)
    • Company와 Reporter의 구현객체는 느슨하게 결합이 되어 있다. 
    • Company의 소스코드 변경없이 Company가 사용할 Repoter구현객체를 변경할 수 있다. 
    • Company는 확장에는 열려있고, 변화에는 닫혀있다. (개방-폐쇄의 원칙)
      • 인터페이스 Report에 대해서만 사용했는데, ChartReporter를 쓰다가 ExcelReporter사용할 수 있다. 소스코드는 안바꿔도됨!!!

Reporter인터페이스의 구현 클래스 개발자 

  • Reporter 출력기능을 제공하는 모든 구현 클래스는 Report인터페이스를 구현한다. 
    • 레포트 출력기능을 제공하는 모든 객체는 동일한 사용법을 가진다. (PrintReport();엑셀이나 차트레포트 동일한 메소드를 사용하도록 작성된다.)
    • 레포트 출력기능을 제공하는 모든 객체는 Reporter타입이다. 
    • 레포트 출력기능을 제공하는 모든 객체는 Reporter타입으로 형변환이 가능하다. 
    • 레포트 출력기능을 제공하는 모든 객체는 Reporter타입의 참조변수로 참조할 수 있다. 
    • 레포트 출력기능을 제공하는 모든 객체는 Reporter와 메소드재정의 관계에 있기 때문에 Reporter타입의 참조변수로 실제 생성된 객체의 재정의된 기능을 실행할 수 있다. (자동으로 됨) ->인터페이스만 끼어놓는데도 이런 효과가 나타남

인터페이스를 이용한 개발 

  • Company 개발자와 Report구현클래스개발자가 서로 독립적으로 개발할 수 있다. 
  • Company클래스와 Report구현클래스가 느슨한 결합으로 조립된다. 
  • Company클래스의 확장성이 높아진다. 
  • 새로운 레포트 출력기능을 쉽게 추가할 수 있다. 
  • 인터페이스만 하나 사용했을 뿐인데, 이렇게 됨. 
  • 추상화란 인터페이스는 구현클래스의 명세서만 할 뿐, 재정의를 강제하는 것은 추상화이다. 
  • 인터페이스면?! 
    1. 표준안
    2. 느슨한 결합
    3. 교체가 가능하다.
    4. 동일한 사용법 이라는 말이 자동으로 나와야한다. 
반응형
Comments