Nice way of factory method pattern with inheritance

守給你的承諾、 提交于 2020-01-02 16:54:40

问题


Suppose I have following class hierarchy:

class abstract Parent{}

class FirstChild extends Parent {}

class SecondChild extends Parent {}

And I'd like to create DTO objects from each child:

class abstract ParentDTO {}

class FirstChildDTO extends ParentDTO{}

class SecondChildDTO extends ParentDTO{}

I think I need a factory method something like this:

ParentDTO createFrom(Parent source); 

Is there any nice way to do this in Java without instanceof checks and if/else statements?

EDIT: This factory method does not work:

public ParentDTO create(Parent source)
{
    return _create(source);
}

private FirstChildDTO _create(FirstChild source)
{
    return new FirstDTO();
}

private SecondChildDTO _create(SecondChild source)
{
    return new SecondDTO();
}

private ParentDTO _create(Parent source)
{
    return new ParentDTO();
}

It only generates ParentDTOs and here is why:

Parent p = new FirstChild();
System.out.println(factory.create(p));  //ParentDTO

FirstChild f = new FirstChild();
System.out.println(factory.create(f));  //FirstChildDTO

回答1:


If you insist on using a factory for DTO creation you can use simple method overloading. Example follows:

public class Factory {

    public ParentDTO createDTO(Parent parent) {
        return new ParentDTO();
    }
    public FirstChildDTO createDTO(FirstChild firstChild) {
        return new FirstChildDTO();
    }
    public SecondChildDTO createDTO(SecondChild SecondChild) {
        return new SecondChildDTO();
    }
}

public class Parent {
}

public class FirstChild extends Parent {
}

public class SecondChild extends Parent {
}

public class ParentDTO {

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }
}

public class FirstChildDTO extends ParentDTO {

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }
}

public class SecondChildDTO extends ParentDTO {

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }
}

public class App {

    public static void main(String[] args) {
        Factory factory = new Factory();
        ParentDTO parentDTO = factory.createDTO(new Parent());
        System.out.println(parentDTO);
        FirstChildDTO firstChildDTO = factory.createDTO(new FirstChild());
        System.out.println(firstChildDTO);
        SecondChildDTO secondChildDTO = factory.createDTO(new SecondChild());
        System.out.println(secondChildDTO);
    }
}

Running the App as Java application in my IDE outputs:

ParentDTO
FirstChildDTO
SecondChildDTO




回答2:


That's quite a complex question. I'd resolve this in few steps.

  1. Parent class should have some kind of interface that would allow your factory to recognize, what data should your DTO object contain, like this (in PHP language):

    class Parent
    {    
         abstract function getDataFields();    
    }
    
    class FirstChild extends Parent
    {    
         function getDataFields()
         {
             return ['id' => $this->id, 'name' => $this->name, 'email' => $this->email];   
         }    
    } 
    
    class SecondChild extends Parent
    {    
        function getDataFields()
        {
            return ['id' => $this->id, 'brand' => $this->brand, 'model' => $this->model];
        }    
    }
    
  2. Now, you only need a single factory, AND i would use a single class for DTO too, since you know what subclass of Parent

    class DTOFactory
    {
        function createFromParent(Parent $parent)
        {
            return new DTO($parent);
        }   
    }
    
    class DTO
    {
        private $fields = [];
    
        function __construct(Parent $parent)
        {
             foreach ($parent->getDataFields() as $field => $value) {
                 $this->fields[$field] = $value
             } 
        }
    
        function __get($field)
        {
             return $this->fields[$field];
        }
    }
    

Of course, there are a lot of ways to make DTO's in various languages, i can't cover this in detail, that's up to you.

  1. You could do your factory method static, but if you want to avoid that, you have to use Dependency Injection of some sorts:

    class MyController
    {
        private $dtoFactory;
    
        function __construct(DTOFactory $factory)
        {
            $this->dtoFactory = $factory;
        }
    
        function returnDTOAction()
        {
            $object = new FirstChild(); // or some other way to get your child;
            return $this->factory->createFromParent($object);
        }
    }
    
    class DIContainer
    {
        private $instances = [];
    
        function get($className)
        {
            if (!is_object($this->instances[$className]) {
                $this->instances[$className] = new $className;                
            }
    
            return $this->instances[$className] = new $className;       
        }
    }
    
    $container = new DIContainer;
    
    $controller = new MyController($container->get('DTOFactory'));
    

This is a very simple example of DI Container, better examples have automatic dependency resolution, so you simply call them like $container->get('MyController'); and get a class with automatically resolved dependencies, but i won't go into further detail on this, since their implementation is heavily language-dependent, and i only stuck with a basic one.

Anyways, hope this helps. If you need some clarifications - feel free to comment.




回答3:


You can code the factory method directly into the model class and utilize Java's covariant return type to return the correct type of DTO, for example:

public class Parent {

    public ParentDTO createDTO() {
        return new ParentDTO();
    }
}


public class FirstChild extends Parent {

    @Override
    public FirstChildDTO createDTO() {
        return new FirstChildDTO();
    }
}


public class SecondChild extends Parent {

    @Override
    public SecondChildDTO createDTO() {
        return new SecondChildDTO();
    }
}


来源:https://stackoverflow.com/questions/30025483/nice-way-of-factory-method-pattern-with-inheritance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!