2016-03-31 4 views
0

Я должен управлять сборами для клиентов. Я создал класс под названием Due. Он хранит взносы для двух типов клиентов X, Y. Все идет так.Должен ли я использовать наследование класса или нет?

public abstract class Due { 

    private CustomerType customerType; //can be either X or Y 
    protected DueType dueType; 
    private String dueId; 
    private BigDecimal dueAmount; 
    private Date dueDate; 

    public Due(CustomerType type) { 
    this.customerType = type; 
    } 

    //getters , setters goes here. 
} 

Также DueType различны для обоих X и Y. Таким образом, я сделал интерфейс с именем DueType и перечислений XDueType, YDueType реализует его.

public interface DueType { 
} 

public enum XDueType implements DueType { 
    A, B; 
} 

public enum YDueType implements DueType { 
    C, D; 
} 

И у меня есть два разных класса, каждый специально предназначенный для X и Y. Как это

public class XDue extends Due { 

    public XDue() { 
    super(CustomerType.X); 
    } 

    public XDueType getDueType() { 
    return (XDueType) this.dueType; 
    } 

} 

public class YDue extends Due { 

    public YDue() { 
    super(CustomerType.Y); 
    } 

    public YDueType getDueType() { 
    return (YDueType) this.dueType; 
    } 
} 

я должен сделать много операций на Due независимо от его типа (эти операции будут одинаковыми для XDue или YDue).

Мой вопрос: следует ли использовать наследование здесь, как указано выше, или нет. Я мог бы сделать только один класс Только. Это могло бы просто сделать работу для меня. Но первый метод кажется мне более семантически правильным. Также, в будущем XDue, YDue может стать менее похожим. Поэтому я считаю, что лучше отделить их отныне. Я прав?

+0

Возможный дубликат (HTTP: // StackOverflow.com/questions/49002/prefer-composition-over-inheritance) – MaxG

+1

Почему вы создали пустой интерфейс без абстрактных методов? – Logan

+0

На это нельзя ответить без семантической информации о том, как отличаются XDue и YDue, как они? – IceFire

ответ

0

Звучит так, как будто класс нуждается в рефакторинге - его сочетание наследования и композиции на данный момент. Я предлагаю идти полностью в одну или другую сторону

Полное наследование перенесет всю условную логику в производные кланы, и любые возвращенные «типы» будут безстоящими синглтонами (для этого подходят перечисления). В идеале, с небольшим дополнительным рефакторингом, вы можете перемещать любой тип депиантного кода, который также включает эти типы в производные классы.

public enum DueType { X, Y } 
public enum CustomerType {X,Y} 

public abstract class Due { 

    private String dueId; 
    private BigDecimal dueAmount; 
    private Date dueDate; 

    public Due(CustomerType type) { 
    this.customerType = type; 
    } 

    abstract DueType getDueType(); 
    abstract CustomerType getCustomerType(); 
} 

public class XDue extends Due { 

    @Override public DueType getDueType() { 
    return DueType.X; 
    } 

    @Override public CustomerType getCustomerType() { 
    return CustomerType.X; 
    } 
} 

Или перейдите в полную композицию, где Due является окончательным и отклоняет его решения к содержащимся стратегическим типам. Опять любая логика, которая включает тип, обычно может быть перенесена в классы Strategy.

public interface DueType /* Really a strategy now */ { 
    void doSomeThing(Due d); 
} 

public interface CustomerType /* Really a strategy now */ { 
    void doSomething(Due d); 
} 

public final class Due { 

    private String dueId; 
    private BigDecimal dueAmount; 
    private Date dueDate; 
    DueType dueType; 
    CustomerType customerType;  

    public Due(CustomerType type, DueType dueType) { 
    this.customerType = type; 
    this.dueType = dueType 
    } 
} 

public class XDueType implements DueType { 
... 
} 

public clasx XCustomerType implements CustomerType { 
... 
} 

Преимущества композиции над наследованием является то, что уборщик реализовать дополнительные вариации на DueType и тип клиентов, которые не имеют никакого отношения, т.е. Due объекта с CustomerTypeA и DueTypeB, без необходимости создания DueAB класса. (Но если это невозможно в вашей ситуации, этот потенциал для различий - это плохо).

Еще одно преимущество заключается в том, что вы можете изменять стратегии во время выполнения без создания совершенно нового объекта Due. Но опять же это может быть не что-то, что необходимо/желательно.

0

Да, вы на правильном пути. Это король шаблона шаблона. Одна вещь, которую вы можете использовать дженериков, так как у вас есть из-за и клиентом того же типа: [? Предпочитаете состава по наследству]

public abstract class Due<T, U> { 

    private U customerType; //can be either X or Y 
    protected T dueType; 
    private String dueId; 
    private BigDecimal dueAmount; 
    private Date dueDate; 

    public Due(Utype) { 
    this.customerType = type; 
    } 

    //getters , setters goes here. 
}