将服务逻辑与数据分离

Sam*_*Sam 15 java service design-patterns

我一直在查看我在android项目中的几个类,我意识到我一直在混合逻辑和数据.在意识到这对我的项目的可读性和测试能力有多糟糕之后,我决定进行一些重构,以便将所有服务逻辑抽象出来以分离服务模块.但是,由于我一直依赖Java的多态性,我迷路了,需要一些指导.

假设我有一个超级数据类的"待更改"布局,以及两个子类:

public class DataItem {
    /* some variables */ 

    public saveToDB(/* Some Arguments */) {
        /* do some stuff */
    }

    public render() {
        /* render the class */
    }
}

public class ChildDataItemA extends DataItem {
    @Override
    public saveToDB(/* Some Arguments */) {
        super.saveToDB(); 
        /* more specific logic to ChildDataItemA */
    }

    @Override
    public render() {
        /* render logic for ChildDataItemA */
    }
}

public class ChildDataItemB extends DataItem {
    @Override
    public saveToDB(/* Some Arguments */) {
        super.saveToDB(); 
        /* more specific logic to ChildDataItemB */
    }

    @Override
    public render() {
        /* render logic for ChildDataItemB */
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我考虑将saveToDB()render()方法移动到服务类.但是,有时我需要能够在DataItem不知道其运行时类型的情况下将这些方法调用到已编译类型的实例中.例如,我可能想要进行以下调用:

List<DataItem> dataList; 
for (DataItem item: dataList) {
    item.saveToDB();
    item.render();
}
Run Code Online (Sandbox Code Playgroud)

另外,我想到了以下几点:

public class ChildDataItemB extends DataItem {
    @Override
    public saveToDB(/* Some Arguments */) {
        super.saveToDB(); 
        /* more specific logic to ChildDataItemB */
         Service.saveToDBB();
    }

    @Override
    public render() {
        /* render logic for ChildDataItemB */
        Service.renderB();
    }
}
Run Code Online (Sandbox Code Playgroud)

我仍然在每个子类中保留"虚拟"方法,这些方法将调用适当的服务方法.但是,我不认为这真的实现了我想要的分离,因为数据类仍然会知道服务(糟糕!).

关于如何解决这个问题的任何想法?

编辑:请注意,render()saveToDB()只是什么这些方法可以通用的例子,所以这个问题是不是真正的选择一个ORM或SQL相关技术.

cas*_*nca 5

访客模式救援.创建访问者界面并让每个服务实现此界面:

public interface DataItemVisitor {
  // one method for each subtype you want to handle
  void process(ChildDataItemA item);
  void process(ChildDataItemB item);
}

public class PersistenceService implements DataItemVisitor { ... }
public class RenderService implements DataItemVisitor { ... }
Run Code Online (Sandbox Code Playgroud)

然后每个都DataItem实现一个accept方法:

public abstract class DataItem {
  public abstract void accept(DataItemVisitor visitor);
}

public class ChildDataItemA extends DataItem {
  @Override
  public void accept(DataItemVisitor visitor) {
    visitor.process(this);
  }
}

public class ChildDataItemB extends DataItem {
  @Override
  public void accept(DataItemVisitor visitor) {
    visitor.process(this);
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,所有accept实现看起来都相同,但是this指的是每个子类中的正确类型.现在,您无需更改DataItem类即可添加新服务.