ABAP Clean Code

ABAP 클린 코드 - METHOD 메서드 (객체 지향 메서드) [10-2]

Dev Do 2024. 8. 25. 22:24
반응형
“정적 메서드보다 인스턴스를 사용하라“는 객체지향 프로그래밍에서 정적 메서드(static methods)를 남용하지 말고, 인스턴스 메서드(instance methods)를 사용해 객체의 상태와 행동을 관리하라는 지침입니다. 이 지침은 객체지향 원칙을 잘 따르기 위한 설계 원칙으로, 코드의 유연성과 재사용성을 높이는 데 중점을 둡니다.

 

정적 메서드와 인스턴스 메서드의 차이점

 

정적 메서드

  • 정적 메서드는 클래스에 속한 메서드로, 객체를 생성하지 않고도 클래스 이름으로 직접 호출할 수 있습니다.
  • 정적 메서드는 주로 상태를 가지지 않으며, 외부에서 전달된 인수만을 사용하여 작업을 수행합니다.
  • 정적 메서드는 특정 기능(예: 유틸리티 함수)을 수행할 때 유용하지만, 클래스와 객체의 상태를 관리하는 데는 적합하지 않습니다.
* 정적 메서드
CLASS lcl_math DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS: add IMPORTING iv_num1 TYPE i
                             iv_num2 TYPE i
                  RETURNING VALUE(rv_sum) TYPE i.
ENDCLASS.

CLASS lcl_math IMPLEMENTATION.
  METHOD add.
    rv_sum = iv_num1 + iv_num2.
  ENDMETHOD.
ENDCLASS.

DATA(lv_result) = lcl_math=>add( 10, 20 ).

 

인스턴스 메서드

  • 인스턴스 메서드는 객체에 속한 메서드로, 객체를 생성한 후 해당 객체를 통해 호출됩니다.
  • 인스턴스 메서드는 객체의 상태(인스턴스 변수)에 접근할 수 있으며, 객체가 가지고 있는 데이터를 변경하거나 처리하는 데 사용됩니다.
  • 객체 지향 설계 원칙에 따르면, 객체의 상태와 관련된 작업은 인스턴스 메서드에서 처리하는 것이 바람직합니다.
* 인스턴스 메서드
CLASS lcl_calculator DEFINITION.
  PUBLIC SECTION.
    METHODS: constructor IMPORTING iv_initial_value TYPE i,
             add IMPORTING iv_num TYPE i
             RETURNING VALUE(rv_result) TYPE i.
  PRIVATE SECTION.
    DATA: current_value TYPE i.
ENDCLASS.

CLASS lcl_calculator IMPLEMENTATION.
  METHOD constructor.
    current_value = iv_initial_value.
  ENDMETHOD.

  METHOD add.
    current_value = current_value + iv_num.
    rv_result = current_value.
  ENDMETHOD.
ENDCLASS.

DATA(lo_calculator) = NEW lcl_calculator( 10 ).
DATA(lv_result) = lo_calculator->add( 20 ).

 

왜 정적 메서드보다 인스턴스 메서드를 사용하는 것이 좋은가?

 

1. 유연성

  • 인스턴스 메서드는 객체의 상태를 관리할 수 있어, 각 객체가 독립적으로 자신의 상태를 유지할 수 있습니다. 이는 정적 메서드에서는 불가능한 일입니다. 여러 객체가 독립적으로 동작해야 하는 경우, 인스턴스 메서드를 사용하는 것이 더 유연합니다.
  • 여러 사용자 정보를 다루는 객체가 각각의 정보를 관리할 수 있게 하려면, 인스턴스 메서드를 사용해 각 객체가 고유한 상태를 가지도록 하는 것이 바람직합니다.

2. 객체지향 원칙 준수

  • 객체지향 프로그래밍(OOP)의 핵심은 캡슐화(encapsulation), 상속(inheritance), 다형성(polymorphism)을 통해 코드의 재사용성을 높이고, 유지보수를 쉽게 하는 것입니다. 정적 메서드는 이러한 객체지향 원칙을 따르지 않는 경우가 많습니다.
  • 인스턴스 메서드는 객체의 행동(메서드)과 상태(속성)를 캡슐화하여, 객체가 더 자율적으로 동작할 수 있게 합니다.

3. 테스트와 유지보수 용이성

  • 인스턴스 메서드는 상태를 유지하면서 독립적으로 동작할 수 있어, 유닛 테스트를 더 쉽게 할 수 있습니다. 객체별로 상태를 관리할 수 있기 때문에, 테스트 시 각각의 객체를 독립적으로 검증할 수 있습니다.
  • 정적 메서드는 전역 상태를 사용하거나 외부 종속성을 가질 가능성이 높아, 테스트가 어렵고 유지보수가 힘들어질 수 있습니다.

4. 상속과 다형성 지원

  • 인스턴스 메서드는 상속을 통해 확장 가능하며, 다형성을 지원할 수 있습니다. 자식 클래스가 부모 클래스의 메서드를 재정의(오버라이딩)할 수 있어, 코드의 유연성과 재사용성이 높아집니다.
  • 정적 메서드는 상속을 통한 다형성을 지원하지 않기 때문에, 객체지향 설계에서 제한적입니다.
“정적 메서드보다 인스턴스를 사용하라“는 객체지향 설계에서 정적 메서드 대신 인스턴스 메서드를 사용해 객체의 상태와 행동을 관리하라는 의미입니다. 인스턴스 메서드를 사용하면 객체의 상태를 유지하고, 상속과 다형성을 통해 코드의 유연성과 재사용성을 높일 수 있습니다. 반면, 정적 메서드는 상태를 관리하지 않으며, 객체지향 원칙을 따르지 않기 때문에 제한적으로 사용해야 합니다.

 

“공용 인스턴스 메서드는 항상 인터페이스의 일부여야 한다“는 객체지향 설계 원칙 중 하나로, 공용(Public)으로 정의된 인스턴스 메서드가 클래스 내부에만 국한되지 않고 인터페이스(interface)를 통해 외부에 노출되어야 한다는 의미입니다. 이 지침은 객체지향 설계의 유연성과 확장성을 높이고, 클래스의 결합도를 줄이는 데 중점을 둡니다.

 

왜 공용 인스턴스 메서드는 인터페이스의 일부여야 하는가?

 

1. 추상화(Abstraction)

  • 인터페이스는 클래스의 구현을 추상화합니다. 인터페이스를 통해 클래스가 제공하는 기능(메서드)은 외부에 노출되지만, 내부 구현은 숨겨집니다. 이를 통해 사용자(클라이언트)는 클래스의 내부 동작을 알 필요 없이 인터페이스만 보고 해당 기능을 사용할 수 있습니다.
  • 공용 인스턴스 메서드를 인터페이스에 포함하면, 구현이 아닌 계약(Contract)을 기반으로 코드가 작성되므로, 클래스의 내부 구현 변경이 클라이언트 코드에 영향을 미치지 않습니다.

2. 유연성

  • 인터페이스를 사용하면 다양한 클래스가 동일한 기능을 제공할 수 있습니다. 클라이언트 코드에서는 인터페이스에 정의된 메서드를 호출하고, 실제 구현은 각기 다른 클래스가 담당하게 됩니다. 이는 다형성(Polymorphism)을 지원하며, 프로그램의 유연성을 높입니다.
  • 공용 인스턴스 메서드가 인터페이스의 일부가 되면, 여러 클래스가 이 인터페이스를 구현할 수 있으므로 새로운 기능을 쉽게 확장할 수 있습니다.

3. 테스트 용이성

  • 인터페이스를 사용하면 클라이언트 코드에서 구체적인 클래스 대신 인터페이스에 의존하게 됩니다. 이를 통해 의존성 주입(Dependency Injection)이나 Mock 객체를 활용한 테스트가 더 쉬워집니다.
  • 인터페이스를 통해 메서드를 호출하면, 테스트 시에 실제 클래스 대신 가짜(Mock) 구현을 주입하여 테스트할 수 있습니다.

4. 결합도 낮추기

  • 인터페이스를 사용하면 클래스 간의 결합도가 낮아집니다. 클라이언트 코드가 인터페이스에 의존하게 되면, 구체적인 클래스 구현에 대한 의존성이 줄어들어, 클래스 간의 결합도가 낮아지고, 시스템 전체의 유연성과 유지보수성이 향상됩니다.

5. 유지보수성

  • 인터페이스를 통해 공용 메서드를 관리하면, 클래스의 내부 구현을 변경하더라도 인터페이스를 따르는 한 클라이언트 코드에 영향을 미치지 않습니다. 이는 변경에 강한 코드를 작성할 수 있게 하며, 유지보수가 쉬워집니다.
* 인터페이스 없이 공용 인스턴스 메서드 사용
CLASS lcl_vehicle DEFINITION.
  PUBLIC SECTION.
    METHODS: start_engine,
             stop_engine.
ENDCLASS.

CLASS lcl_vehicle IMPLEMENTATION.
  METHOD start_engine.
    WRITE: / 'Engine started'.
  ENDMETHOD.

  METHOD stop_engine.
    WRITE: / 'Engine stopped'.
  ENDMETHOD.
ENDCLASS.

DATA(lo_vehicle) = NEW lcl_vehicle( ).
lo_vehicle->start_engine( ).

 

* 인터페이스를 통한 공용 메서드 사용
INTERFACE lif_vehicle.
  METHODS: start_engine,
           stop_engine.
ENDINTERFACE.

CLASS lcl_vehicle DEFINITION.
  PUBLIC SECTION.
    INTERFACES: lif_vehicle.
ENDCLASS.

CLASS lcl_vehicle IMPLEMENTATION.
  METHOD lif_vehicle~start_engine.
    WRITE: / 'Engine started'.
  ENDMETHOD.

  METHOD lif_vehicle~stop_engine.
    WRITE: / 'Engine stopped'.
  ENDMETHOD.
ENDCLASS.

DATA(lo_vehicle) = NEW lcl_vehicle( ).
DATA(lo_vehicle_intf) = CAST lif_vehicle( lo_vehicle ).
lo_vehicle_intf->start_engine( ).

 

“공용 인스턴스 메서드는 항상 인터페이스의 일부여야 한다“는 공용으로 노출되는 인스턴스 메서드가 있을 때, 이를 인터페이스의 일부로 정의하여 외부에 노출하고, 클래스 내부의 구현은 인터페이스를 통해 추상화하라는 의미입니다. 이 지침을 따르면 코드의 유연성, 테스트 용이성, 유지보수성이 향상되며, 객체지향 원칙을 더 잘 준수할 수 있습니다.
반응형