使用哪种模式来避免代码重复与对象值转换器

Chr*_*311 5 java polymorphism abstract-class code-duplication

我想摆脱下面的代码重复MyFacadeBean.考虑以下情况:

public class FacadeBean implements Facade {

    @EJB
    private CrudService crudService;

    @Inject
    private FirstAssembler firstAssembler;
    @Inject
    private SecondAssembler secondAssembler;
    @Inject
    private ThirdAssembler thridAssembler;
    @Inject
    private FourthAssembler fourthAssembler;

    @Override
    public void save(FirstValue value) {
        FirstEntity entity = this.firstAssembler.transformToEntity(value);
        this.crudService.persist(entity);
    }

    @Override
    public void save(SecondValue value) {
        SecondEntity entity = this.secondAssembler.transformToEntity(value);
        this.crudService.persist(entity);
    }

    @Override
    public void save(ThirdValue value) {
        ThirdEntity entity = this.thirdAssembler.transformToEntity(value);
        this.crudService.persist(entity);
    }

    @Override
    public void save(FourthValue value) {
        FourthEntity entity = this.fourthAssembler.transformToEntity(value);
        this.crudService.persist(entity);
    }

}

public interface MyFacade {

    void save(FirstValue value);

    void save(SecondValue value);

}
Run Code Online (Sandbox Code Playgroud)

随着CrudService:

public interface CrudService {

    void persist(Object entity);

}

@Stateless
@Local(CrudService.class)
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class CrudServiceBean implements CrudService {

    public static final String PERSISTENCE_UNIT_NAME = "my_persistence_unit";

    private EntityManager entityManager;

    @PersistenceContext(unitName = PERSISTENCE_UNIT_NAME)
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public void persist(Object entity) {
        this.entityManager.persist(entity);
    }

}
Run Code Online (Sandbox Code Playgroud)

使用以下汇编程序:

public class FirstAssembler extends AbstractAssembler<FirstEntity> {

    public FirstEntity transformToEntity(FirstValue value) {
        if (value == null)
            return null;
        FirstEntity entity = new FirstEntity();
        transformAbstractValueToAbstractObject(value, entity);
        entity.setFixedRate(value.getFixedRate());
        entity.setStartDate(value.getStartDate());
        return entity;
    }

}

public class SecondAssembler extends AbstractAssembler<SecondEntity> {

    public SecondEntity transformToEntity(SecondValue value) {
        if (value == null)
            return null;
        SecondEntity entity = new SecondEntity();
        transformAbstractValueToAbstractObject(value, entity);
        entity.setTransactionType(value.getTransactionType());
        entity.setValueDate(value.getValueDate());
        return entity;
    }

}

public abstract class AbstractAssembler<T extends AbstractEntity> {

    protected void transformAbstractValueToAbstractObject(AbstractValue value, T object) {
        object.setUniqueId(value.getUniqueId());
        object.setNominalAmountValue(value.getNominalAmountValue());
    }

}
Run Code Online (Sandbox Code Playgroud)

使用以下实体:

@Entity
public class FirstEntity extends AbstractEntity {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ID")
    private Long id;
    @Column(name = "START_DATE")
    @Temporal(TemporalType.DATE)
    private Date startDate;
    @Column(name = "FIXED_RATE")
    @Digits(integer = 1, fraction = 10)
    private BigDecimal fixedRate;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getStartDate() {
        return startDate;
    }

    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    public BigDecimal getFixedRate() {
        return fixedRate;
    }

    public void setFixedRate(BigDecimal fixedRate) {
        this.fixedRate = fixedRate;
    }

}


@Entity
public class SecondEntity extends AbstractEntity {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ID")
    private Long id;
    @Column(name = "VALUE_DATE")
    @Temporal(TemporalType.DATE)
    private Date valueDate;
    @Column(name = "TRANSACTION_TYPE")
    @Enumerated(EnumType.STRING)
    private TransactionType transactionType;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getValueDate() {
        return valueDate;
    }

    public void setValueDate(Date valueDate) {
        this.valueDate = valueDate;
    }

    public TransactionType getTransactionType() {
        return transactionType;
    }

    public void setTransactionType(TransactionType transactionType) {
        this.transactionType = transactionType;
    }

}

@MappedSuperclass
public abstract class AbstractEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    @Column(name = "TRANSACTION_NOM_AMOUNT_VALUE")
    @Digits(integer = 18, fraction = 5)
    @Min(0)
    private BigDecimal nominalAmountValue;

    public BigDecimal getNominalAmountValue() {
        return nominalAmountValue;
    }

    public void setNominalAmountValue(BigDecimal nominalAmountValue) {
        this.nominalAmountValue = nominalAmountValue;
    }

}
Run Code Online (Sandbox Code Playgroud)

我尝试了以下方法:

public class FacadeBean implements Facade {
    @Inject
    private Assembler assembler;

    @Inject
    private AssemblerFactory assemblerFactory;

    @Override
    public <T extends AbstractValue> void save(T value) {
        Assembler assembler = assemblerFactory.createAssembler(value);
        AbstractEntity entity = assembler.transformToEntity(value);
        this.crudService.persist(entity);
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是AssemblerFactoryImpl和AssemblerImpl,我必须在其中执行instanceOf检查和转换...

另一个想法是让值知道使用哪个变换器(或如何变换).但我希望价值"愚蠢".

@Glenn Lane

public AbstractValue save(AbstractValue value) {
    AbstractAssembler<AbstractValue, AbstractEntity> assembler = new FirstAssembler();
    AbstractEntity entity = assembler.transformToEntity(value);
    AbstractValue result = assembler.transformToValue(entity);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

不起作用,因为

类型不匹配:无法从FirstAssembler转换为AbstractAssembler

Men*_*ena 2

使用带有绑定类型参数的泛型方法可以避免重复:

public <T extends AbstractValue> T save(T value) {...}

在方法主体中,您将能够使用valueAbstractValue.

笔记

  • 由于您的save方法在本示例中似乎被覆盖,因此您可能还需要更改父类或接口的设计。
  • 您还可以使用泛型类作为开始(而不是非必要的泛型类中的泛型方法),具体取决于您的用例。