具有继承性的工厂方法模式的好方法
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();
}
它只生成 ParentDTO
s,原因如下:
Parent p = new FirstChild();
System.out.println(factory.create(p)); //ParentDTO
FirstChild f = new FirstChild();
System.out.println(factory.create(f)); //FirstChildDTO
这是一个相当复杂的问题。我会分几步解决这个问题。
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];
}
}
现在,你只需要一个工厂,我也会为 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,我无法详细介绍,这取决于您。
你 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
假设我有以下 class 层次结构:
class abstract Parent{}
class FirstChild extends Parent {}
class SecondChild extends Parent {}
我想从每个 child:
创建 DTO objectsclass 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();
}
它只生成 ParentDTO
s,原因如下:
Parent p = new FirstChild();
System.out.println(factory.create(p)); //ParentDTO
FirstChild f = new FirstChild();
System.out.println(factory.create(f)); //FirstChildDTO
这是一个相当复杂的问题。我会分几步解决这个问题。
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]; } }
现在,你只需要一个工厂,我也会为 DTO 使用一个 class,因为你知道
Parent
的子classclass 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,我无法详细介绍,这取决于您。
你
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