2015-05-04 70 views
2

假設我有下面的類層次結構:很好的方式

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

是否有任何不錯方法來做到這一點在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 
+0

在Java中,[在繼承青睞組成](HTTPS://書籍.google.be/books?id = ka2VUBqHiWkC&pg = PA81)。它會產生你不想要/不需要的問題和頭痛。 –

+0

@OlivierGrégoire謝謝,我牢記這一點。 – mtyurt

回答

2

上使用工廠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); 
    } 
} 

運行App如在我的IDE輸出Java應用程序:

ParentDTO
FirstChildDTO
SecondChildDTO

+0

這是我嘗試的第一件事,但它不起作用。只有'ParentDTO'實例以這種方式創建。 – mtyurt

+0

我剛試過這個,它似乎爲我工作。我將編輯我的答案以提供詳細信息。你可以在你的機器上試試嗎? – iluwatar

+0

是的,這工作正常。我正在嘗試另一個案例,我正在用它更新問題。 – mtyurt

1

這是一個相當複雜的問題。我會在幾個步驟中解決這個問題。

  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. 現在,你只需要一個工廠,因爲你知道什麼子類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,我無法詳細說明這一點,這取決於您。

  • 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');,並獲得一個具有自動解決的依賴關係的類,但我不會在這方面進一步細節,因爲他們的實現是嚴重的語言 - 依賴,而我只有s掖着一個基本的。

    無論如何,希望這有助於。如果你需要一些澄清 - 隨時發表評論。

    +0

    在動態語言中做得很好。也許我應該限制這個問題到Java :) – mtyurt

    +0

    我沒有那種Java經驗,但我想你使用'HashMap'作爲你的'DTO'字段鍵值存儲,就是這樣。而且,據我所知,Java有很多DI-Containers的實現,所以這也不會成爲問題。 – Eternal1

    +0

    @ Eternal1 Java是嚴格鍵入的,並且HashMap並沒有真正作爲值對象的替代品被引入。儘管您的建議可以在Java中輕鬆實現,但理想情況下應避免使用。 – CKing

    0

    您可以直接編寫工廠方法到模型類,並利用Java的covariant return type返回正確類型的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(); 
        } 
    } 
    
    +0

    對不起,這個想法是解耦模型和DTO。 – mtyurt

    +0

    沒問題。你應該選擇最適合你的設計。請檢查我的其他答案。 – iluwatar