Several tables that should represent a single entity

7

I'm updating a system that has eleven tables that represent a single entity, I believe by implementation error, as shown below:

Entidade: Foo

Tabela Foo1 - Campo1, Campo2, Campo3
Tabela Foo2 - Campo1, Campo2, Campo3
Tabela Foo3 - Campo1, Campo2, Campo3, Campo4
[...]

Because of this implementation, there are eleven entities in the system that inherit from Foo, with their respective repositories and services. This implementation has had a direct impact on the code, which has n switchs that defines which entity should be used. The cases has the same code, except for the repositories and services used.

Database and entity refactoring is currently not an option.

Given this scenario, what would be the best approach to deal with this situation? The code so far should not be changed, but there is a great effort to create new functionalities that depend on this architecture of N tables and N entities that should represent only one. Is there any design pattern that can make this work easier?

The project architecture is in Onion with MVC Presentation Layer. The MVC layer accesses the services that in turn encapsulate the system business rule. A common problem with this implementation is that whenever something involves these entities and tables, a switch needs to be done to define which service will be called to communicate with the database.

public class FooService{
    private service1;
    private service2;
    //demais services das entidades

    //construtor

    public void Inserir(Entidade foo)
    {
        switch(bar.TipoItem)
        {
            case(TipoItemEnum.Tabela1):
                service1.RealizarAlgumProcesso(foo);
                break;
            case(TipoItemEnum.Tabela2):
                service2.RealizarAlgumProcesso(foo);
                break;
            //demais cases para os demais services.
        }   
    }
}
    
asked by anonymous 13.02.2015 / 13:13

3 answers

3

Yes. Her name is Helper , which is a variation of Utility .

Since the methods are very similar, you can centralize the common business logic within Helper and call only one method that does everything.

Please put examples of business logic in the question I put in the answer how to refactor your logic to a Helper .

Service Layer

Assuming your example, I can reimplement a Service using a generic approach. For example:

public class ClasseService<T>
    where T: Foo 
{
    public void RealizarAlgumProcesso(T objeto) 
    {
        ...
    }
}

Derived type specific checks can be done as follows:

if (obj.GetType() == typeof(Foo1)) { ... }

I know it's not yet appropriate, but it's a starting point.

    
13.02.2015 / 13:49
1

In .NET 4.0 we have the option of dynamic, I would not recommend using it lightly, but in your situation it may come in handy.

Create a factory that takes the table type as the parameter and returns the corresponding service, so as to avoid refactoring the code and creating an interface (s) and programming polymorphically you can use dynamic and invoke the method in runtime. The counterpoint is intellisense performance and loss.

This will only work if all services have the same method names.

Ex:

    public static class MyFactory
    {
        public static dynamic GetService(TableType type)
        {
            switch (type)
            {
                case TableType.Table1:
                    return new Service1();
                case TableType.Table2:
                    return new Service2();
                case TableType.Table3:
                    return new Service3();
                default:
                    return null;
            }
        }
    }

    public enum TableType 
    {
        Table1,
        Table2,
        Table3,
    }


public class Service1 { public int Xpto(int i) { return i; } }
public class Service2 { public double Xpto(double d) { return d; } }
public class Service3 { public string Xpto(string s) { return s; } }

Use with return and different parameters:

var service = MyFactory.GetService(TableType.Table1);
Console.WriteLine(service.Xpto(1));

service = MyFactory.GetService(TableType.Table2);
Console.WriteLine(service.Xpto(4.0));

service = MyFactory.GetService(TableType.Table3);
Console.WriteLine(service.Xpto("Xpto"));
    
22.02.2015 / 04:13
0

The service architecture must follow the same entity architecture and for this you must use the polymorphism of your service objects and encapsulate only what each needs. In the given example, a more flexible implementation would be to create a generic interface that contains the method to be used and create a service for each entity type that implements that interface. You will need a selector class, which is one that will have only the logic of what is on the switch. That way all code will be with the encapsulation due. Here is the refactoring of the example you posted:

public class FooService
{
    public void Inserir(object foo)
    {
        IService insertService = InsertServiceSelector.GetService(foo);
        insertService.RealizarAlgumProcesso(foo);
    }
}

interface IService
{
    void RealizarAlgumProcesso(object foo);
}

class StringService : IService
{
    public void RealizarAlgumProcesso(object foo)
    {
        string bar = (string) foo;
        /* ...Serviço para Strings... */
    }
}

class IntegerService : IService
{
    public void RealizarAlgumProcesso(object foo)
    {
        int bar = (int) foo;
        /* ...Serviço para inteiros.. */
    }
}

class InsertServiceSelector
{
    public static IService GetService(object foo)
    {
        if(foo is string)
            return new StringService();

        if (foo is int)
            return new IntegerService();

        /*... A lógica de seleção fica encapsulada...*/

    }
}
    
22.02.2015 / 17:02