Você percebe que seu código, na sua forma atual, permite que várias instâncias de LCL_CARRIER existam, representando a mesma companhia aérea. Para corrigir isso, você definirá e implementará um método factory que garante que somente uma instância possa ser criada para um determinado valor de ID de transportadora.
Tarefa 1: Copiar modelo (opcional)
Copie a classe modelo /LRN/CL_S4D401_OOS_INTF_USAGE. Se você tiver concluído o exercício anterior, pode ignorar esta tarefa e continuar processando sua classe ZCL_##_SOLUTION.
Etapas
Copie a classe /LRN/CL_S4D401_OOS_INTF_USAGE para uma classe em seu próprio pacote (nome sugerido: ZCL_##_SOLUTION, onde ## representa seu número de grupo).
No Explorador de projetos, clique com o botão direito do mouse na classe /LRN/CL_S4D401_OOS_INTF_USAGE para abrir o menu de contexto.
No menu de contexto, selecione Duplicar....
Insira o nome do seu pacote no campo Pacote. No campo Nome, insira ZCL_##_SOLUTION, em que ## representa seu número de grupo.
Selecione Avançar.
Confirme a ordem de transporte e selecione Concluir.
Ative a cópia.
Pressione Ctrl + F3 para ativar a classe.
Tarefa 2: Definir um método factory
Utilize uma correção rápida para definir um método factory para a classe local LCL_CARRIER (nome proposto: GET_INSTANCE). No método factory, execute a verificação de existência e a verificação de autorização antes de criar realmente uma instância. Em seguida, restrinja a criação de instância para esta classe para forçar a utilização do método factory.
Etapas
Na classe local LCL_CARRIER, utilize uma solução rápida para definir um método factory.
Dica
Os parâmetros do construtor são adicionados à assinatura do método factory por padrão. Por isso, não selecione explicitamente o atributo carrier_id como atributo a ser inicializado.
Navegue para a definição de LCL_CARRIER.
Na instrução CLASS … DEFINITION, posicione o cursor em lcl_carrier e pressione Ctrl + 1 para chamar as correções rápidas disponíveis.
A partir da lista de soluções rápidas disponíveis, selecione Gerar criação de método de fábrica.
No campo Nome, insira GET_INSTANCE.
Na seção Selecionar atributos para inicializar, selecione Desmarcar tudo e, em seguida, selecione Concluir.
A correção rápida deve ter adicionado a seguinte definição de método:
12345
CLASS-METHODS get_instance
IMPORTING
i_carrier_id TYPE /dmo/carrier_id
RETURNING
value(r_result) TYPE REF TO lcl_carrier.
… e a seguinte implementação:
123
METHOD get_instance.
r_result = NEW #( i_carrier_id = i_carrier_id ).
ENDMETHOD.
Desloque a instrução SELECT e a instrução AUTHORITY-CHECK do CONSTRUCTOR para a implementação do método factory. Certifique-se de executar as verificações antes da instanciação.
Navegue para a implementação do método CONSTRUCTOR da classe local LCL_CARRIER.
Selecione a instrução SELECT e a instrução AUTHORITY-CHECK, incluindo a avaliação do campo do sistema SY-SUBRC e o acionamento da exceção, e pressione Ctrl + C para copiar o snippet de código para o clipboard.
Pressione Ctrl + < para adicionar um sinal de comentário na frente de cada linha de código selecionada.
Navegue para a implementação do método GET_INSTANCE, posicione o cursor antes da atribuição de valor para o parâmetro r_result e pressione Ctrl + V para inserir o snippet de código.
O código deve ter o seguinte aspecto:
12345678910111213141516171819202122
METHOD get_instance.
SELECT SINGLE
FROM /lrn/carrier
FIELDS concat_with_space( carrier_id, name, 1 ), currency_code
WHERE carrier_id = @i_carrier_id
INTO ( @me->name, @me->currency_code ).
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.
AUTHORITY-CHECK
OBJECT '/LRN/CARR'
ID '/LRN/CARR' FIELD i_carrier_id
ID 'ACTVT' FIELD '03'.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_auth_check_exception.
ENDIF.
r_result = NEW #( i_carrier_id = i_carrier_id ).
ENDMETHOD.
Uma vez que você removeu as instruções RAISE EXCEPTION da implementação do método CONSTRUCTOR, elimine agora os dois suplementos RAISING correspondentes na assinatura da definição de método CONSTRUCTOR.
Navegue para a definição do método CONSTRUCTOR em LCL_CARRIER.
Ajuste a definição do método da seguinte forma:
123456
METHODS constructor
IMPORTING
i_carrier_id TYPE /dmo/carrier_id
.
Volte para a implementação do método GET_INSTANCE. Na instrução SELECT, ajuste a cláusula INTO. Armazena o resultado em uma estrutura declarada inline (nome sugerido: detalhes) em vez de nome de atributos de instância e currency_code.
Ajuste o código da seguinte forma:
1234567
SELECT SINGLE
FROM /lrn/carrier
FIELDS concat_with_space( carrier_id, name, 1 ) AS name,
currency_code
WHERE carrier_id = @i_carrier_id
INTO @DATA(details).
Após a instanciação do objeto de suporte, atribua os valores da estrutura detalhada aos atributos de instância correspondentes da nova instância.
Ajuste o código da seguinte forma:
12345
r_result = NEW #( i_carrier_id = i_carrier_id ).
r_result->name = details-name.
r_result->currency_code = details-currency_code.
ENDMETHOD.
Utilize uma correção rápida para adicionar declarações de aumento para as duas exceções.
Selecione o ícone de advertência com a lâmpada no lado esquerdo da primeira instrução RAISE EXCEPTION para chamar as soluções rápidas disponíveis.
Na lista de soluções rápidas disponíveis, selecione Adicionar declaração de criação.
Repita isso para a outra instrução RAISE EXCEPTION.
A correção rápida deve ter ajustado o código da seguinte forma:
12345678
CLASS-METHODS get_instance
IMPORTING
i_carrier_id TYPE /dmo/carrier_id
RETURNING
value(r_result) TYPE REF TO lcl_carrier
RAISING
cx_abap_invalid_value
cx_abap_auth_check_exception.
Restrinja a instanciação da classe local LCL_CARRIER. Certifique-se de que a instanciação só é permitida dentro da própria classe.
Navegue para a definição de LCL_CARRIER.
Ajuste o código da seguinte forma:
1
CLASS lcl_carrier DEFINITION CREATE PRIVATE.
Desloque a definição do método CONSTRUCTOR para a seção privada.
Nota
Isso é opcional, mas deve ser feito para melhorar a legibilidade.
Copie e cole a instrução METHODS para o método CONSTRUCTOR da seção pública para a seção privada.
No método IF_OO_ADT_CLASSRUN~MAIN da classe global, substitua a expressão NEW por uma chamada do método factory GET_INSTANCE.
Ajuste o código da seguinte forma:
12
DATA(carrier) = lcl_carrier=>get_instance( i_carrier_id = c_carrier_id ).
No método CLASS_SETUP da classe de teste local LTCL_FIND_FLIGHTS, substitua a expressão NEW por uma chamada do método factory GET_INSTANCE.
Ajuste o código da seguinte forma:
12
the_carrier = lcl_carrier=>get_instance( i_carrier_id = some_flight_data-carrier_id ).
Ative e teste sua classe global como aplicativo de console. Depurar a execução do método GET_INSTANCE.
Pressione Ctrl + F3.
Pressione F9.
Tarefa 3: Ampliar o método factory
Na classe local LCL_CARRIER, defina um atributo estático no qual você pode armazenar referências às instâncias de LCL_CARRIER (nome sugerido: instâncias). Em seguida, estenda a implementação do método factory: após a criação de uma instância, armazene a referência à nova instância em instâncias de atributo. Crie uma nova instância somente se as instâncias ainda não referenciarem um objeto para o ID de agente de frete solicitado.
Etapas
Na classe local LCL_CARRIER, utilize uma correção rápida para criar um tipo de tabela para esta classe (nome proposto: tt_carrier).
Navegue para a definição da classe local LC_CARRIER.
Na instrução CLASS … DEFINITION, posicione o cursor em lcl_carrier e pressione Ctrl + 1 para chamar as correções rápidas disponíveis.
A partir da lista de soluções rápidas disponíveis, selecione Gerar tipo de tabela para lcl_carrier.
Na nova instrução TYPES, substitua a ficha de registro por tt_carrier.
A instrução TYPES deve ter o seguinte aspecto:
12
TYPES: tt_carriers TYPE STANDARD TABLE OF REF TO lcl_carrier
WITH DEFAULT KEY.
Defina um atributo estático privado com base no tipo de tabela recém-criado (nome sugerido: instâncias).
Role para baixo até a instrução PRIVATE SECTION.
Ajuste o código da seguinte forma:
12
PRIVATE SECTION.
CLASS-DATA instances TYPE tt_carriers.
Ajuste a implementação do método factory GET_INSTANCE. Após a instanciação, adicione uma referência à nova instância ao atributo de instâncias.
Ajuste o código da seguinte forma:
123456
r_result = NEW #( i_carrier_id = i_carrier_id ).
r_result->name = details-name.
r_result->currency_code = details-currency_code.
APPEND r_result TO instances.
ENDMETHOD.
Antes da instanciação, mas após as verificações de existência e de autorização, implemente um registro individual lido a partir de instâncias de atributo. Leia a instância na qual o valor do atributo carrier_id é igual ao valor do parâmetro de importação i_carrier_id. Arquive o resultado no parâmetro de retorno r_result.
Dica
Lembre-se de que, em tabelas internas com tipo de linha não estruturado, você aborda os dados usando pseudocomponente table_line.
Ajuste o código da seguinte forma:
1234567891011
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_auth_check_exception.
ENDIF.
r_result = instances[ table_line->carrier_id = i_carrier_id ].
r_result = NEW #( i_carrier_id = i_carrier_id ).
r_result->name = details-name.
r_result->currency_code = details-currency_code.
APPEND r_result TO instances.
Envolver o acesso de leitura de registro individual, a instanciação, as avaliações dos atributos e a instrução APPEND com um TRY... Estrutura de controle ENDTRY.
Ajuste o código da seguinte forma:
123456789
TRY.
r_result = instances[ table_line->carrier_id = i_carrier_id ].
r_result = NEW #( i_carrier_id = i_carrier_id ).
r_result->name = details-name.
r_result->currency_code = details-currency_code.
APPEND r_result TO instances.
ENDTRY.
Certifique-se de que você só cria uma instância e a adiciona a instâncias de atributo, se a exceção de sistema CX_SY_ITAB_LINE_NOT_FOUND for acionada.
Ajuste o código da seguinte forma:
123456789
TRY.
r_result = instances[ table_line->carrier_id = i_carrier_id ].
CATCH cx_sy_itab_line_not_found.
r_result = NEW #( i_carrier_id = i_carrier_id ).
r_result->name = details-name.
r_result->currency_code = details-currency_code.
APPEND r_result TO instances.
ENDTRY.
Na sua classe global, ajuste a implementação do método IF_OO_ADT_CLASSRUN~MAIN: implemente uma segunda chamada para o método factory GET_INSTANCE com a mesma entrada que a chamada existente, mas uma variável de referência diferente para o resultado (nome proposto: carrier2).
Ajuste o código da seguinte forma:
12
DATA(carrier) = lcl_carrier=>get_instance( i_carrier_id = c_carrier_id ).
DATA(carrier2) = lcl_carrier=>get_instance( i_carrier_id = c_carrier_id ).
Ative e teste sua classe global como aplicativo de console. Depurar o código para garantir que as duas chamadas do método factory retornam a mesma instância de LCL_CARRIER.
Pressione Ctrl + F3.
Pressione F9.