2015-12-31 56 views
0

我正在研究一個複雜的數據模型,其中我們有不同的類,其中有許多屬性,我們有時需要比較或複製部分屬性。但是,我們無法將它們聚集在一堂課中,因爲其中有些重疊。java中的幾種克隆和比較

所以,你可以更好的瞭解,讓我們舉一個例子:

public class Product { 
    private Amount price; 
    private String name; 
    private String description; 
    private Color color; 
    private Shape shape; 
    private Picture mainPicture; 
    private Company designer; 
    private Company maker; 
} 

讓我們想象一下生產外包,我們有時需要複製的一切,但製造商:

public Product copyForOutsourcing(Product product) { 
    Product p = new Product(); 
    p.setPrice(product.getPrice()); 
    p.setName(product.getName()); 
    p.setDescription(product.getDescription()); 
    p.setColor(product.getColor()); 
    p.setShape(product.setShape()); 
    p.setMainPicture(product.getMainPicture()); 
    p.setDesigner(product.getDesigner()); 
    return p; 
} 

現在讓我們來想象一下該產品存在多種形式,我們有時需要複製一切,但形狀,顏色和圖片:

public Product copyForDeclension(Product product) { 
    Product p = new Product(); 
    p.setPrice(product.getPrice()); 
    p.setName(product.getName()); 
    p.setDescription(product.getDescription()); 
    p.setDesigner(product.getDesigner()); 
    p.setMaker(product.getMaker()); 
    return p; 
} 

同樣,我們需要不同的比較:p1.get *()。equals(p2.get *())。如你所見,它有點多餘,當有更多的屬性和/或更多的拷貝或比較方法時,它仍然是最差的。而且,當添加屬性時,我們總是忘記將它添加到複製和比較方法中。

我們得到的第一個想法是添加註釋:

@Outsourcing, @Declension 
    private Amount price; 
    @Outsourcing, @Declension 
    private String name; 
    @Outsourcing, @Declension 
    private String description; 
    @Outsourcing, @Declension 
    private Color color; 
    @Outsourcing 
    private Shape shape; 
    @Outsourcing 
    private Picture mainPicture; 
    @Outsourcing 
    private Company designer; 
    @Declension 
    private Company maker; 

這樣一來,很容易比較或複製使用反射屬性,沒有多餘的代碼,並添加屬性時,可以很容易地更新副本並比較方法:我們只需要添加註釋到新的屬性。

但是,如果產品擴展了其他類,讓我們說CompanyObject,應該在copyForDeclension中複製像「stockingLocations」這樣的屬性。 CompanyObject不應依賴註釋Declension,因爲此註釋是特定於產品的。 CompanyObject甚至可能在其他項目中,因此無法修改。

如果我們要使用反射,從而避免冗餘,那麼我們需要指定複製哪些屬性:

public List<Field> getDeclensionAttributes() { 
    List<Field> list = new ArrayList<Field>(); 
    list.add(ReflectUtils.getField(CompanyObject.class, "stockingLocation")); 
    list.add(ReflectUtils.getField(Product.class, "price")); 
    ... 
    return list; 
} 

的問題是,這樣一來,我們的屬性指定爲字符串,從而重構遺囑指定可能會破壞事情,編譯器不會警告我們!

所以問題是:當需要指定多個複製/比較方法的許多屬性的類時,實現這些複製和比較方法的最優雅的方法是什麼? 此外,如何確保添加屬性迫使開發人員在不同的複製/比較方法中質疑此屬性的行爲?

+0

那麼,如果你使用彈簧,你可以設計自定義產品工廠類,它可以根據你的要求給你產品對象。 – Nir

+0

註釋你不要複製的內容可能更有意義(例如@NotCopiedForDeclension)。 –

+0

作爲比較,在您的Product Domain中使用java.util.Comparator接口的多個實現作爲內部類。 – Sunny

回答

0

也許您可以只有一個副本實現,並通過傳遞要拷貝的屬性List(Enum來表示屬性列表)來控制要複製的屬性。這樣

public Product copyForDeclension(Product product, List<ProductAttributes> attribuitesToCopy) { 
    attribuitesToCopy.stream().forEach(productAttribute -> { 
     switch (productAttribute) { 
      case PRICE: 
       //do copy 
       break; 
      case NAME: 
       //do copy 
       break; 
      default: 
       // throw exception, will be helpful for maintain code 
     } 

    }); 
} 

enum ProductAttributes { 
    PRICE, 
    NAME, 
    //..... 
} 

這種方式實現的東西將是常見的和非冗餘和什麼都屬性被considiered將通過複製調用者(這可能是好還是壞你的要求)來處理。

+0

問題是,如果我們有一個擴展Product的類MyProduct,它將不得不列出產品的所有屬性在它自己的枚舉MyProductAttributes中,所以我們仍然有冗餘。 – Niolak

+0

只有一個枚舉可以保持說ProductAttributes這將具有產品和層次結構的屬性 – sourabh