简体   繁体   English

OO设计-该设计有缺陷吗?

[英]OO design - is this design flawed?

I am creating a logic for web application to managing consents from user. 我正在为Web应用程序创建逻辑来管理用户的同意。

The model class that is persisted in the DB will have multiple fields, from which only a set will be changed with user request. 保留在数据库中的模型类将具有多个字段,根据用户请求,其中只有一组将被更改。 E. g. 例如 class will have 10 fields with various consents, but user will be willing to change only 2 of those. 班级将有10个字段,并有各种同意,但用户只愿意更改其中2个。 To avoid writing a big chain of if-else's I designed this classes, to harness polymorphism to do the job for me, but somehow this design seems flawed to me. 为了避免编写大量if-else链,我设计了此类,以利用多态性为我完成工作,但是在某种程度上,这种设计对我来说是有缺陷的。 Could you tell me if this is proper way to do it? 您能告诉我这是否是正确的方法吗?

PROBLEM: Change values of only subset of fields from large set of fields in class. 问题:仅从类的大量字段中更改字段子集的值。

For sake of simplicity I removed getter/setters methods and some fields. 为了简单起见,我删除了getter / setters方法和一些字段。 Main logic for changing consents: 变更同意书的主要逻辑:

public class GdprServiceImpl implements GdprService {

private final ConsentRepository consentRepository;

@Autowired
public GdprServiceImpl(ConsentRepository consentRepository) {
    this.consentRepository = consentRepository;
}

@Override
public void changeConsent(User user, List<ConsentDto> consents) {
    Optional<Consent> optionalConsent = consentRepository.findByUser(user);
    if(optionalConsent.isPresent()) {
        Consent consent = optionalConsent.get();
        for(ConsentDto consentDto : consents) {
            consentDto.apply(consent);
        }
        consentRepository.save(consent);
    }
    else {
        Consent consent = new Consent();
        consent.setUser(user);
        for(ConsentDto consentDto : consents) {
            consentDto.apply(consent);
        }
        consentRepository.save(consent);
    }
}

Model class: 型号类别:

public class Consent {

    private Boolean messageConsent;
    private Boolean recordConsent;
    /*CONSTRUCTOR, OTHER METHODS AND FIELDS OMITTED*/
}

Classes that will change a set of fields from Consent class: 将更改同意类的一组字段的类:

public abstract class ConsentDto {

    public abstract void apply(Consent consent);
}



public class RecordConsentDto extends ConsentDto {

   private boolean consentValue;

   public RecordConsentDto(boolean consentValue) {
        this.consentValue = consentValue;
    }

    @Override
    public void apply(Consent consent) {
        consent.setRecordConsent(consentValue);
    }
}



public class MessageConsentDto extends ConsentDto {

    private boolean consentValue;

    public MessageConsentDto(boolean consentValue) {
        this.consentValue = consentValue;
    }

    @Override
    public void apply(Consent consent) {
        consent.setMessageConsent(this.consentValue);
    }
}

You are right about the design having a "smell". 您对具有“气味”的设计是正确的。
This is because the DB design is not normalized. 这是因为数据库设计未标准化。
having a list of consents in one record is an indication. 在一条记录中列出同意列表是一种指示。 while technically it is allowed, classic RDBMS design dictatets that arrays should be represented as either one-to-many or many-to-many relation between tables. 虽然从技术上讲是允许的,但是经典的RDBMS设计要求将数组表示为表之间的一对多或多对多关系。 Of course, same in the object model. 当然,对象模型也一样。

a Fully normalized solution will have a consent_catalog table and many-to-many relation to users: 完全规范化的解决方案将具有一个accept_catalog表以及与用户的多对多关系:

table consent_catalog {
  int id // PK
  String name
}

The catalog acts as "consent enum", having one row per type of consent (record, message, etc) 目录充当“同意枚举”,每种同意类型(记录,消息等)都有一行

table user_consents {
  int user_id references users(id)
  int consent_id references consent_catalog(id)
}

This table has rows only for consents accepted by the user. 该表仅具有用于用户接受的同意的行。 no "false" consents. 没有“假”同意。 This design opens up new possibilities like knowing which users have a specific consent or mulitple consents in common. 这种设计开辟了新的可能性,例如知道哪些用户具有特定的同意或共同同意。

This design feels like an overkill. 这种设计感觉有点过分。 At the end of the day you are always calling consent.setMessageConsent() or similar it's wrapped with an enum field and a class implementing ConsumerDto (which is really a Consumer ). 在一天结束时,您总是要调用consent.setMessageConsent()或类似的方法,它被枚举字段和实现ConsumerDto的类包装(实际上是Consumer )。 Generally DTO are not supposed to implement business logic yet one could argue that apply method is one. 通常,DTO不应实现业务逻辑,但人们可以认为apply方法是一种。

It really would be cleaner to have UserConsent POJO with Boolean fields. 拥有带Boolean字段的UserConsent POJO确实更干净。 The exception would be if triggering one consent should trigger other but it's not clear from your example. 例外情况是,如果触发一个同意应触发另一个同意,但您的示例尚不清楚。

Just my two cents. 只是我的两分钱。 I'd prefer to see either an anemic POJO passed around or DDD aggregate root for user that manages consents but not something in between. 我更希望看到传递的是贫乏的POJO或DDD的聚集根,该根用于管理同意的用户,但介于两者之间却没有。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM