具有继承性的工厂方法模式的好方法

Nice way of factory method pattern with inheritance

假设我有以下 class 层次结构:

class abstract Parent{}

class FirstChild extends Parent {}

class SecondChild extends Parent {}

我想从每个 child:

创建 DTO objects
class abstract ParentDTO {}

class FirstChildDTO extends ParentDTO{}

class SecondChildDTO extends ParentDTO{}

我想我需要一个像这样的工厂方法:

ParentDTO createFrom(Parent source); 

有没有好的方法在Java中做到这一点而不需要instanceof检查和if/else语句?

编辑: 此工厂方法不起作用:

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();
}

它只生成 ParentDTOs,原因如下:

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

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

这是一个相当复杂的问题。我会分几步解决这个问题。

  1. Parent class 应该有某种接口可以让你的工厂识别,你的 DTO 对象应该包含什么数据,就像这样(在PHP 语言):

    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. 现在,你只需要一个工厂,我也会为 DTO 使用一个 class,因为你知道 Parent 的子class

    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];
        }
    }
    

当然,有很多方法可以用各种语言制作 DTO,我无法详细介绍,这取决于您。

  1. could 做你的静态工厂方法,但如果你想避免这种情况,你必须使用某些类型的 Dependency Injection

    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'));
    

这是DI Container的一个非常简单的例子,更好的例子有自动依赖解析,所以你只需像$container->get('MyController');那样调用它们并得到一个class自动解析依赖,但是我不会对此进行更详细的介绍,因为它们的实现在很大程度上依赖于语言,而且我只坚持使用一个基本的。

无论如何,希望这对您有所帮助。如果您需要一些说明 - 请随时发表评论。

您可以将工厂方法直接编码到模型中 class 并利用 Java 的 covariant return type 到 return 正确的 DTO 类型,例如:

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();
    }
}

如果您坚持使用工厂来创建 DTO,您可以使用简单的方法重载。示例如下:

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);
    }
}

运行 应用程序作为 Java 应用程序在我的 IDE 输出中:

ParentDTO
FirstChildDTO
SecondChildDTO