我想摆脱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);
}
使用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);
}
}
使用以下汇编程序:
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());
}
}
使用以下实体:
@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;
}
}
我尝试了以下方法:
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);
}
}
问题是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;
}
由于,不起作用
类型不匹配:无法从FirstAssembler转换为AbstractAssembler
答案 0 :(得分:3)
我将此作为单独的答案发布,因为我并不认为为每个AbstractValue类型设置保存方法有任何问题。
首先,我们将为此示例建立您的基值类。我正在使用界面,所以我们不会在水面上浑浊。您的AbstractValue
界面:
public interface AbstractValue
{
int getUniqueId();
double getNominalValue();
<T> T accept(AbstractValueVisitor<T> visitor);
}
&#34;访客界面&#34;:
public interface AbstractValueVisitor<T>
{
T visit(FirstValue value);
T visit(SecondValue value);
T visit(ThirdValue value);
T visit(FourthValue value);
}
我知道您不希望将智能融入AbstractValue
,但我们将添加一个规范... AbstractValue
的所有具体实现(所有四个方法都以这种方式实现accept
方法:
@Override
public <T> T accept(AbstractValueVisitor<T> visitor)
{
return visitor.visit(this);
}
因此该方法实现四次次:在所有四个值类中,完全相同的方式。因为访问者接口知道所有具体实现,所以将为每个特定值类型调用适当的方法。所有这三个部分放在一起的是#34;访客模式&#34;。
现在我们将建立一个实体工厂。它的工作是在提供AbstractEntity
:
AbstractValue
public class AbstractEntityFactory
implements AbstractValueVisitor<AbstractEntity>
{
private static final AbstractEntityFactory INSTANCE;
static
{
INSTANCE = new AbstractEntityFactory();
}
// Singleton pattern
private AbstractEntityFactory()
{
}
public static AbstractEntity create(AbstractValue value)
{
if (value == null)
{
return null;
}
AbstractEntity e = value.accept(INSTANCE);
e.setNominalValue(value.getNominalValue());
e.setUniqueId(value.getUniqueId());
return e;
}
@Override
public AbstractEntity visit(FirstValue value)
{
FirstEntity entity = new FirstEntity();
// Set all properties specific to FirstEntity
entity.setFixedRate(value.getFixedRate());
entity.setStartDate(value.getStartDate());
return entity;
}
@Override
public AbstractEntity visit(SecondValue value)
{
SecondEntity entity = new SecondEntity();
// Set all properties specific to SecondEntity
entity.setTransactionType(value.getTransactionType());
entity.setValueDate(value.getValueDate());
return entity;
}
@Override
public AbstractEntity visit(ThirdValue value)
{
ThirdEntity entity = new ThirdEntity();
// Set all properties specific to ThirdEntity
return entity;
}
@Override
public AbstractEntity visit(FourthValue value)
{
FourthEntity entity = new FourthEntity();
// Set all properties specific to FourthEntity
return entity;
}
}
现在您的外观实现需要AbstractValue
,并且您获得了一个您正在寻找的保存方法:
public class FacadeBean implements Facade
{
@EJB
private CrudService crudService;
@Override
public void save(AbstractValue value)
{
AbstractEntity entity = AbstractEntityFactory.create(value);
crudService.persist(entity);
}
}
因为您的AbstractValue
现在遵循访客模式,所以您可以执行各种多态行为。如:
public class AbstractValuePrinter implements AbstractValueVisitor<Void>
{
private final Appendable out;
public AbstractValuePrinter(Appendable out)
{
this.out = out;
}
private void print(String s)
{
try
{
out.append(s);
out.append('\n');
}
catch (IOException e)
{
throw new IllegalStateException(e);
}
}
@Override
public Void visit(FirstValue value)
{
print("I'm a FirstValue!");
print("Being a FirstValue is groovy!");
return null;
}
@Override
public Void visit(SecondValue value)
{
print("I'm a SecondValue!");
print("Being a SecondValue is awesome!");
return null;
}
@Override
public Void visit(ThirdValue value)
{
print("I'm a ThirdValue!");
print("Meh.");
return null;
}
@Override
public Void visit(FourthValue value)
{
print("I'm a ThirdValue!");
print("Derp.");
return null;
}
}
在此示例中,此访问者不会返回任何内容...它正在做&#34;做&#34;因此,我们只需将返回值设置为Void
,因为它不可实例化。然后您只需打印该值:
// (value must not be null)
value.accept(new AbstractValuePrinter(System.out));
最后,访问者模式中最酷的部分(在我看来):你添加FifthValue
。您将新方法添加到访问者界面:
T visit(FifthValue value);
突然,你无法编译。您必须解决在两个地方缺少此处理的问题:AbstractEntityFactory
和AbstractValuePrinter
。这很棒,因为你应该在那些地方考虑它。进行课堂比较(使用instanceof
或rinde的班级到工厂地图的解决方案)很可能会错过&#34;新的值类型,现在你有运行时错误...特别是如果你用这些值类型做100个不同的事情。
Anyhoo,我不想进入这个,但你去了:)
答案 1 :(得分:2)
使用带有绑定类型参数的泛型方法,以避免重复:
public <T extends AbstractValue> T save(T value) {...}
在方法正文中,您可以使用与value
相关的所有方法引用参数AbstractValue
。
备注强>
save
方法似乎已被覆盖,因此您可能还需要更改父类或接口的设计。答案 2 :(得分:0)
我认为代码中的一个问题是AbstractAssembler
的泛型类型是transform方法的输出,而不是输入。如果您按如下方式进行更改:
public abstract class AbstractAssembler<T extends AbstractValue> {
protected void transformAbstractValueToAbstractObject(AbstractEntity entity, T value) {
entity.setUniqueId(value.getUniqueId());
entity.setNominalAmountValue(value.getNominalAmountValue());
}
public abstract AbstractEntity transformToEntity(T value);
}
然后,您可以将FacadeBean
更改为以下内容。
public class FacadeBean {
@EJB
private CrudService crudService;
final Map<Class<?>, AbstractAssembler<?>> knownAssemblers;
FacadeBean() {
knownAssemblers = new LinkedHashMap<>();
knownAssemblers.put(FirstValue.class, new FirstAssembler());
knownAssemblers.put(SecondValue.class, new SecondAssembler());
// add more assemblers here
}
public <T extends AbstractValue> void save(T value, Class<T> type) {
@SuppressWarnings("unchecked") // safe cast
final AbstractAssembler<T> assembler =
(AbstractAssembler<T>) knownAssemblers.get(type);
final AbstractEntity entity = assembler.transformToEntity(value);
this.crudService.persist(entity);
}
}
请注意,我更改了save(..)
方法的签名,以便我们拥有需要保存的对象的类型。使用这种类型,我们可以简单地查找应该使用的正确汇编程序。并且因为汇编程序现在在其输入类型上是通用的,我们可以进行安全转换(小心保持地图一致)。
此实现避免了代码重复,因为您只需要一个保存方法。通过更改instanceof
的泛型类型并将所有汇编程序存储在映射中,可以防止使用AbstractAssembler
运算符。
汇编程序可能如下所示:
public class FirstAssembler extends AbstractAssembler<FirstValue> {
@Override
public FirstEntity transformToEntity(FirstValue value) {
final FirstEntity entity = new FirstEntity();
// do transformational stuff
super.transformAbstractValueToAbstractObject(entity, value);
entity.setFixedRate(value.getFixedRate());
entity.setStartDate(value.getStartDate());
return entity;
}
}
public class SecondAssembler extends AbstractAssembler<SecondValue> {
@Override
public SecondEntity transformToEntity(SecondValue value) {
final SecondEntity entity = new SecondEntity();
// do transformational stuff
super.transformAbstractValueToAbstractObject(entity, value);
return entity;
}
}
注意:我不熟悉Java bean,因此如果您想使用@Inject
ed汇编程序而不是调用构造函数,则可能需要稍微修改代码直接
答案 3 :(得分:0)
你在这里接近镀金,但你可以做一些减少,特别是>>> ships = [item['name'] for item in data['ships'].values()]
>>> ships
9: [u'Viper_MkIV', u'SideWinder', u'Asp', u'Type7', u'SideWinder']
>>>
- 检查并调用每个扩展的常用字段设置方法。
columnA | columnB | columnC
____________________________
| A | 3 | 2 |
| B | 1 | 5 |
然后是扩展的汇编程序:
null
如果确实希望单个工厂类处理所有值/实体,我会查看访问者模式,使用访问者界面上的泛型类型参数(以及实体/值)进行增强accept方法根据访问接口返回一个类型。我不会在这里展示一个例子,因为我不认为这是你的理由。
答案 4 :(得分:-1)
从保存这些值的类的角度来看,您可以使用一种保存方法,但仍需要实现三种单独的保存方法。
使用所有三种保存方法实现一个类。例如:
public class ValuePersister {
@Inject
private Assembler1 assembler1;
@Inject
private Assembler2 assembler2;
@Inject
private Assembler3 assembler3;
public Value1 save(Value1 value1, CrudService crudService) {
Entity1 entity1 = assembler1.transformToObject(value1);
crudService.persist(entity1);
return assembler1.transformToValue(entity1);
}
public Value2 save(Value2 value2, CrudService crudService) {
Entity2 entity2 = assembler2.transformToObject(value2);
crudService.persist(entity2);
return assembler2.transformToValue(entity2);
}
public Value3 save(Value3 value3, CrudService crudService) {
Entity3 entity3 = assembler3.transformToObject(value3);
crudService.persist(entity3);
return assembler3.transformToValue(entity3);
}
}
向AbstractValue添加一个抽象方法:
public abstract AbstractValue save(ValuePersister valuePersister, CrudService crudService);
在扩展AbstractValue的每个类中实现该方法:
@Override
public AbstractValue save(ValuePersister valuePersister, CrudService crudService) {
return valuePersister.save(this, crudService);
}
注入ValuePersister并实现原始的通用保存方法:
@Inject
private ValuePersister valuePersister;
@Override
public AbstractValue save(AbstractValue value) {
return value.save(valuePersister, crudService)
}