Objeto com propriedades e métodos personalizados

5

Um projeto em que estou trabalhando atualmente no modelo Order information. No momento, há uma classe com várias propriedades e funções que todos os pedidos têm em comum. Além disso, alguns de nossos usuários personalizaram propriedades e / ou funções na parte superior do pedido base. Algumas dessas propriedades personalizadas são compartilhadas entre vários usuários e algumas são exclusivas para um determinado usuário. A classe tem quase 50 propriedades diferentes, mas um determinado usuário pode estar usando apenas 20 dessas propriedades.

Gostaria de reformulá-lo para que as propriedades / funções de base sejam separadas das propriedades / funções personalizadas, mas não sei como abordar isso. Pensei em herdar a classe base, mas um usuário pode ter 3 ou 4 propriedades personalizadas diferentes. Não há herança clara entre as propriedades customizadas. Eu olhei para o padrão decorador, mas a interface está mudando, então isso não parece se encaixar.

Existe alguma maneira de conseguir isso sem ter a classe monolítica?

Exemplos:

Base Properties - OrderID, OrderDate, AccountId, etc.
Customized Properties - BackOrdered, PONumber, ContactPerson
Base Functions - PlaceOrder, CancelOrder
Customized Functions - AddContact, DiscountPriceByPercent

Assim, alguns usuários podem ter apenas a base, um usuário pode ter a base + BackOrdered e outro usuário pode ter base + BackOrdered + PONumber.

Esse problema não é exclusivo dos pedidos, tenho o mesmo problema com outros objetos no projeto. Eu estou procurando mais por uma arquitetura / padrão para resolver o caso geral do que por uma maneira de lidar com pedidos.

    
por KevenDenen 16.12.2015 / 00:39
fonte

4 respostas

7

Parece-me que as propriedades personalizadas são sobre o estado do processamento de pedidos.

Faça um diagrama de estado do seu processo de pedido. Classes de design que movem o Order de um estado para outro, por exemplo, de um estado backordered para um estado enviado . O núcleo Order estaria contido em cada um deles, conforme estiver passando por essa mudança de estado específica.

Também pode haver uma classe que capture os vários estados em que um pedido passou, à medida que vai de um novo pedido, preenchido, pago, enviado, etc. Se essa "lista de verificação" é uma parte integral da classe Order , é uma questão a ser resolvida pela sua análise de projeto. Pode haver um OrderProcessor que direcione uma ordem pelo labirinto de estado.

P.S.

Minha resposta parece bastante semelhante à resposta do @Ewan , por exemplo "ordem pode ter coisas diferentes acontecendo com eles" No entanto, quero enfatizar os estados com transições entre eles explicitamente definidos em oposição a "serviços" discretos sem relacionamentos definidos.

Em outras palavras, para enviar um pedido, ele deve estar em um determinado estado (preenchido, digamos) e por design , sabemos que passou por todos os estados necessários até o estado atual. Caso contrário, todo "serviço" não relacionado teria que avaliar a ordem de toda a sua cadeia de estados, potencialmente enviando-a de volta para "consertar" - uma tigela potencialmente recursiva de mingau.

    
por 20.12.2015 / 17:29
fonte
1

Se todas as propriedades personalizadas forem conhecidas em tempo de compilação, mas elas puderem ser combinadas de maneiras diferentes e você não quiser produzir uma grande hierarquia de classes, então tou pode usar o Padrão Misto, cuja implementação dependerá da programação linguagem que você usa. Exemplo de código em Java:

interface Mixed {
    <M, I extends M> void extend(Class<M> iface, I impl);
    <M> M as(Class<M> iface);                
}
class MyObject implements Mixed {
     String getP1();
     LocalDate getP2();
}
class CustomFeature1 {
      String getA1();
      String getB1();
}
class CustomFeature2 {
      String getA2();
      String getB2();
}

// O will have properties P1,P2,A1,A2,B1 and B2
MyObject o = new MyObject();
o.extend(CustomFeature1.class, new CustomFeature1());
o.extend(customFeature2.class, new CustomFeature2());
o.as(CustomFeature1.class).getCustomPropertyA1();

Se as propriedades personalizadas forem definidas no tempo de execução, provavelmente, é hora de pensar nas estruturas de dados de tempo de execução definidas por um metamodelo:

interface Property {
    String getName();
    Class<?> getValueType();
    Object getValueFor(Object object);
}
interface Model {
     addProperty(String name, Class<?> valueType);
     List<Property> getProperties();
}
interface DynamicObject {
     Model getModel();
     Object getValue(String propertyName);
     void setValue(String propertyName, Object value);
}
class MyObject implements DynamicObject {
     String getP1();
     String getP2();
}

MyObject o = new MyObject();
// add new custom property
o.getModel().addProperty("A1", String.class);
// set custom property value
o.setValue("A1", "Lorem Ipsum");

// Let's list all custom properties and their values
for (Property property : o.getModel().getProperties()) {         
     System.out.println(property.getName() + "=" + property.getValueFor(o));
}

Em ambas as soluções, você precisará implementar um mecanismo de persistência personalizado para armazenar os dados no banco de dados ou para serializar em XML ou JSON. Você precisará usar reflexão para isso.

    
por 18.12.2015 / 12:48
fonte
0

Para processos de atendimento de pedidos em que tipos diferentes de pedidos podem ter coisas diferentes acontecendo com eles, sugiro que você adote uma abordagem orientada a serviços. Mover a lógica do domínio para fora do objeto em serviços e adicionar um histórico de eventos ao objeto para armazenar seu estado variável.

Ou seja. Em vez de AdvanceOrder e SendNowOrder, os métodos Buy () substituídos têm BuyNowService e PlaceAdvanceOrderService, ambos com um método Buy (Order order).

Você pode enviar pedidos para um ou outro serviço, conforme necessário.

Em vez de AdvanceOrder.DateToPlace e BuyNowOrder.IsInStock, DelayUntillEvent e OutOfStockEvent herdaram de um evento base e armazenaram em Order.Events Only serviços que sabem como lidar com esses eventos precisam referenciá-los.

    
por 16.12.2015 / 01:52
fonte
0

Se o desempenho é o objetivo principal, então eu iria para a solução monolítica. Se a flexibilidade é a única, então pode ser que você possa usar um dicionário chamado 'CustomProps' com o nome e valor das propriedades personalizadas e outro chamado 'CustomFuncs' com o nome e a função que você deseja chamar.

Agora você pode criar um getter / setter com um nome de string e um valor de objeto, encontrar a propriedade e converter o valor. Para as funções analógicas com um nome de string e uma função / ação / delegado, que você pode chamar. Se eles precisarem de parâmetros, isso pode ser melhorado.

Claramente, isso não será o mais rápido, mas muito flexível ...

    
por 20.12.2015 / 16:00
fonte