带inheritance的工厂方法模式的好方法

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

class abstract Parent{} class FirstChild extends Parent {} class SecondChild extends Parent {} 

我想从每个孩子创建DTO对象:

 class abstract ParentDTO {} class FirstChildDTO extends ParentDTO{} class SecondChildDTO extends ParentDTO{} 

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

 ParentDTO createFrom(Parent source); 

有没有很好的方法在没有instanceof检查和if / else语句的情况instanceof在Java中执行此操作?

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

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

它只生成ParentDTO ,这就是原因:

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

如果您坚持使用工厂进行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); } } 

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

ParentDTO
FirstChildDTO
SecondChildDTO

这是一个非常复杂的问题。 我只需几步即可解决这个问题。

  1. Parent类应该有某种接口,允许你的工厂识别你的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使用一个类,因为你知道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]; } } 

当然,有很多方法可以用各种语言制作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'); 并获得一个具有自动解析依赖关系的类,但我不会详细讨论这个问题,因为它们的实现依赖于语言,而且我只是坚持使用基本语言。

无论如何,希望这会有所帮助。 如果您需要一些说明 – 随意评论。

您可以将工厂方法直接编码到模型类中,并利用Java的协变返回类型返回正确类型的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(); } }