Как да споделяме местни класове?

В момента работя върху доста сложно ABAP приложение, което ще бъде разделено на няколко модула, всеки от които изпълнява определена част от работата:

  • един за събиране на някои данни от множество източници;
  • един за показване на тези данни в потребителския интерфейс (SALV мрежа, ако това има значение);
  • един за правене на някои бизнес неща въз основа на тези данни.

Според моя план всеки модул ще бъде глобален клас. Има обаче някаква логика, която може да се наложи да бъде споделена между тези класове: помощни подпрограми, логика за достъп до DB и т.н. Всичко това е набор от локални класове в момента.

Знам, че тези класове биха могли да бъдат и глобални, но това би означавало излагането им (както и редица вътрешни структури от данни) на обществеността, което не бих искал. Друг подход би бил споделянето на включванията с тях между моите глобални класове, но се казва, че това е лош дизайн.

И така, въпросът ми е: как истинските ABAPers решават проблеми като този?


person Alex Kiselev    schedule 30.11.2014    source източник
comment
Особено DB access logic звучи като нужда от друг помощен клас. Може би бихте могли да създадете главен клас и да наследите подпрограмите от този главен клас (но това също може да е много лоша идея - зависи от вашия реален код).   -  person knut    schedule 30.11.2014
comment
Имам помощни класове за това. Загрижеността ми е да намеря начин да ги споделя между модулите на приложението, без да ги правя глобални (т.е. публични).   -  person Alex Kiselev    schedule 30.11.2014


Отговори (4)


Ето пример за това как можете да получите достъп до локален клас, дефиниран в отчет.

Докладът с класа.

REPORT ZZZ_PJ1.

CLASS lcl_test DEFINITION FINAL.
  PUBLIC SECTION.
    METHODS:
      test.
ENDCLASS.

CLASS lcl_test IMPLEMENTATION.
  METHOD test.
    WRITE 'test'.
  ENDMETHOD.
ENDCLASS.

Докладът, който използва класа.

REPORT ZZZ_PJ2.

CLASS lcl_main DEFINITION FINAL CREATE PRIVATE.
  PUBLIC SECTION.
    CLASS-METHODS:
      main.
ENDCLASS.

CLASS lcl_main IMPLEMENTATION.
  METHOD main.
    DATA:
      lr_object TYPE REF TO object.

    CREATE OBJECT lr_object
      TYPE ('\PROGRAM=ZZZ_PJ1\CLASS=LCL_TEST')

    CALL METHOD lr_object->('TEST').
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  lcl_main=>main( ).

Разбира се, това не е умно решение, тъй като всяко извикване на метод трябва да бъде динамично извикване.

CALL METHOD lr_object->('TEST').

Това обаче може да бъде решено чрез използване на глобални интерфейси, които биха дефинирали методите на вашите класове (разбира се, ако не са статични, което предполагам, че не са). След това трябва да контролирате всеки от екземплярите чрез интерфейса. Вашата цел ще бъде изпълнена тогава, тъй като само интерфейсът ще бъде изложен глобално, реализациите ще останат в локални класове.

person Jagger    schedule 01.12.2014
comment
Интересен трик. Въпреки това поддържането на приложения, проектирани по този начин, може лесно да се превърне в катастрофа. Предполагам, че просто ще изоставя идеята с местните класове: споделените неща просто трябва да бъдат изложени на обществеността. - person Alex Kiselev; 01.12.2014
comment
Добро заключение! Използвам локални класове главно за организиране на вътрешната структура на глобален клас (т.е. за изграждане на делегирани обекти, които нямат функция за многократна употреба, но образуват съгласуван набор от логика вътре в глобалния клас). - person rplantiko; 02.12.2014
comment
@AlexKiselev Можете ли да дадете пример за това как нещо може да се превърне в катастрофа? Тук говоря за подхода с използването на глобални интерфейси. За динамичните извиквания на методи мога да се съглася. - person Jagger; 03.12.2014
comment
Имах предвид динамичните разговори основно. Въпреки това, дори в случай на интерфейсен подход, ще може ли списъкът where-used да намери създаването на динамичен обект? Ако не, тогава ето потенциал за истински проблем: един ден някой може да преименува или изтрие локалния клас (той е локален, така че не трябва да се използва отвън, така че трябва да е доста безопасно да се прави каквото и да било с него и т.н. ). - person Alex Kiselev; 04.12.2014
comment
@AlexKiselev Е, списъкът с къде се използва и обектно-ориентираното програмиране звучи по-скоро като тясно свързване, което не е добра идея... И ако някой премахне локалния клас, вашите автоматични регресионни тестове така или иначе ще го хванат, нали? - person Jagger; 04.12.2014
comment
Класовете са отделени чрез въвеждане на интерфейси: това вече е доста OOPish. Ако обектите от тези класове са създадени изрично (т.е. по тип, а не по име на тип, взето от някъде), това не ги прави тясно свързани, тъй като те все още не знаят един за друг, те виждат само интерфейсите. Междувременно всеки може да провери дали този клас се използва някъде. Що се отнася до тестовете: превенцията е по-добра от лечението, предпочитам да мога да проверя дали нещо се използва, отколкото да се занимавам с неуспешните тестове. - person Alex Kiselev; 04.12.2014
comment
Класовете не са нищо като необвързани, когато човек използва CREATE OBJECT с твърдо кодирани имена на класове изрично в целия код. Тогава дори интерфейсите няма да помогнат... - person Jagger; 04.12.2014
comment
Какво не е наред с изричното инстанциране? Да приемем, че имате клас ZA, който се отнася до интерфейса ZI, реализиран от клас ZB. ZA и ZB не са тясно свързани тук, докато ZA не знае нищо за изпълнението на ZI, с което работи в момента. - person Alex Kiselev; 08.12.2014
comment
За край на дискусията. Препоръчвам да свикнете със следните термини: инжектиране на зависимост и разхлабена връзка. IMHO, който никога не е чувал за тези термини или не ги разбира, никога не е програмирал правилно по обектно-ориентиран начин. - person Jagger; 09.12.2014
comment
Е, знам и използвам тези два принципа. И просто не виждам как предишният ми коментар противоречи на който и да е от тях. Все още ли пропускам нещо? - person Alex Kiselev; 09.12.2014

Може да искате да прочетете малко модели за проектиране на модел-изглед-контролер. Показване на данни в потребителски интерфейс - би било "изглед". Както събирането, така и актуализирането на данни ще бъдат включени в „Модел“. Бизнес логиката вероятно трябва да бъде внедрена като взаимодействие между изгледа и модела в „Контролер“.

Въпреки това, един подход към това е да се използва функцията за приятелство, предлагана в ABAP OO.

Като пример: създайте модела и прегледайте класовете глобално, но им позволете само да бъдат инстанцирани частно, след което дайте достъп на частен компонент до контролера. Дефинициите на класовете ще бъдат следните:

CLASS zcl_example_view DEFINITION
  PUBLIC
  FINAL
  CREATE PRIVATE
  GLOBAL FRIENDS zcl_example_controller


CLASS zcl_example_model DEFINITION
  PUBLIC
  FINAL
  CREATE PRIVATE
  GLOBAL FRIENDS zcl_example_controller


CLASS zcl_example_controller DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC

Освен това може да е добра идея да направите контролера сингълтън и да съхранявате препратка към него както в изгледа, така и в модела. Като налагаме, че контролерът IS BOUND, когато изгледът и моделът са инстанцирани, можем ефективно да гарантираме, че тези три класа съществуват както желаете само вие.

person Thomas Matecki    schedule 01.12.2014
comment
Съмнявам се дали съхраняването на препратки към контролера в модела и изгледа отговаря на принципа на MVC (трябва да е обратното), но цялата идея с частен конструктор и приятелство звучи интересно. - person Alex Kiselev; 01.12.2014
comment
Само един коментар, определянето на приятелство между класове никога не звучи интересно, по-скоро плашещо. - person Jagger; 01.12.2014

Връщайки се към първоначалния ви проблем: Звучи ми така, сякаш вече използвате нещо като MVC модел във вашата разработка, така че единственият ви проблем е, че някои процедури трябва да се използват публично и от двата модела, изгледи и контролери.

В този случай силно препоръчвам да поставите тези рутинни процедури в глобални налични класове или да приложите getter методи във вашите вече съществуващи класове за достъп до тези функции.

Всякакви хакове като \PROGRAM=ZZZ_PJ1\CLASS=LCL_TEST понякога са от съществено значение, но не и тук imho.

person XcodeJunkie    schedule 09.01.2015

Ако вашето приложение е толкова голямо, колкото го представяте, трябва да го организирате с помощта на множество пакети. Със сигурност ще трябва да се справите с неща, които не са OO, като функционални модули, обекти от речник на данни и други неща, които не могат да бъдат част от клас, така че използването на класове като основно средство за организиране на вашето приложение няма да работи извън много малки и специализирани приложения.

Освен това, изглежда, че имате някои наистина сериозни недостатъци, вградени в плана ви, ако смятате, че „логиката за достъп до DB“ е нещо, което трябва да бъде „споделено между класове“. Трудно е да се отгатне без допълнителна информация, но силно бих препоръчал да привлечете някой, който има опит в проектирането и внедряването на приложения от такъв мащаб - поне за да разберете правилно основната концепция.

person vwegert    schedule 30.11.2014
comment
Не е толкова голям, че да бъде разделен на отделни пакети и да, осъзнавам, че ще включва неща освен класове. И какво не е наред със споделянето на DB неща? Приложението има множество входни точки и подобни неща може да се наложи да бъдат извлечени в различни модули. - person Alex Kiselev; 30.11.2014
comment
Не оставам с впечатлението, че се опитвате да научите нещо ново, а че търсите някакво чудотворно лекарство, което да направи вашия счупен дизайн да изглежда по-малко счупен. Успех - излизам... - person vwegert; 30.11.2014
comment
не изглежда, че се опитвате да преподавате нещо. Попитайте някой, който знае как да го направи - чудесен съвет, благодаря. Но каква е тази магическа концепция, която трябва да разбера? Развален дизайн - аргументи, предложения? Какво толкова е счупено в него? - person Alex Kiselev; 30.11.2014