java - 如果在验证规则中使用类型代码,如何进行重构以消除类型代码?

标签 java validation design-patterns refactoring

假设我们在向集合中添加新元素之前必须检查一组规则。元素是一些相似类型的对象。所有类型特定的功能都封装在抽象类的子类中。集合包含此抽象类的对象。这些规则适用于类型的条件以及其他约束。因此,项目的抽象父类(super class)具有附加的类型代码。可以将新元素添加到集合中,但由于附加规则,可以删除或替换集合中的其他元素。

在需要重构的代码中,规则的验证被实现为带有嵌套控制流语句的一长段代码。类型代码的验证会破坏封装。控制流语句的单独分支不能定义为集合元素相应子类的方法,因为它们需要检查类型并对集合进行更改。

关于我的案例中的类型代码的其他事实:

  • 类型代码不会影响类的行为
  • 类型代码是不可变的
  • 类型代码被 ItemsManager 用于在添加之前解析一些规则 集合中的新元素。

如何消除类型代码并将规则与类型分开?

以下是此类问题的示例:

Items 的类型特定功能封装在 AbstractItem 子类中。
ItemManager 类的 add 方法破坏了封装。
规则:如果 Type1 的新项具有相同的 SomeUsefull 属性值,则必须删除 Type2 的项正在添加到集合中。

为了简单起见,省略了 ICloneable 和 IComparable 接口(interface)的实现。在现实世界中,集合中的项目是不可变和可克隆的,并且规则系统非常复杂。

abstract class AbstractItem {

    private int Type; // this would like to eliminate
    private int SomeUseful;

    protected AbstractItem(int Type, int Value) {
        this.Type = Type;
        this.SomeUseful = Value;
    }

    public int getType() { return this.Type; }
    public int getSomeUseful() { return this.SomeUseful; }

    @Override
    public String toString() {
        return String.format("Item{Type=%d, Value=%d}", Type, SomeUseful);
    }
}

class ItemType1 extends AbstractItem {
    ItemType1(int Value) { super(1, Value); }
}

class ItemType2 extends AbstractItem {
    ItemType2(int Value) { super(2, Value); }
}

class ItemManager {

    private java.util.ArrayList<AbstractItem> ListOfItems;

    public ItemManager(){
        this.ListOfItems = new java.util.ArrayList<AbstractItem>();
    }

    public void add(final AbstractItem newItem) {
        // this code breaks encapsulation
        switch (newItem.getType()) {
            case 1:
                // do some type dependent operations
                for(AbstractItem i: this.ListOfItems) {
                    if (i.getType()==2 && i.getSomeUseful()==newItem.getSomeUseful()) {
                        this.ListOfItems.remove(i);
                        break;
                    }
                }
                break;
            case 2:
                // do some other type dependent operations
                break;
            default:
                // throw error
        }
        this.ListOfItems.add(newItem);
    }

    @Override
    public String toString() {
        String str = String.format("ItemsManager content");
        for(AbstractItem i: this.ListOfItems) {
            str += String.format("\n\tType = %d, Value = %d", i.getType(), i.getSomeUseful());
        }
        return str;
    }
}

public class Example1 {
    public static void main(String[] arg) {
        System.out.println("Example 1");
        ItemManager im = new ItemManager();
        im.add(new ItemType1(1));
        im.add(new ItemType2(2));
        im.add(new ItemType2(3));
        im.add(new ItemType1(3));
        System.out.println(im.toString());
    }
}

/*
Example 1
ItemsManager content
    Type = 1, Value = 1
    Type = 2, Value = 2
    Type = 1, Value = 3
*/

最佳答案

从@dbugger的答案开始,你可以进一步插入它。 您可以使用双重调度来隐藏类型代码。仍然不是一个完美的解决方案,因为父级对其子级了解太多,但类型代码现在已经消失了。

很难用您给出的示例代码来判断什么是更好的解决方案,因为当您简化时,您删除了有关所涉及项目的所有信息。那里可能有一些东西可以以其他方式用于区分,允许您使用 shoudBeRemovedBecauseType1 摆脱双重调度。

这是对类型 1 进行修改的 onAdd 方法

@Override
public List<AbstractItem> onAdd(List<AbstractItem> list)    {
    for (AbstractItem item : list)      {
        if (item.shoudBeRemovedBecauseType1(this))          {
            list.remove(item);
            break;
        }
    }
    return list;
}

基类中的新方法

    public boolean shoudBeRemovedBecauseType1(ItemType1 itemType1)
    {
        return false;
    }

在类型 2 子类中重写

    @Override
    public boolean shoudBeRemovedBecauseType1(ItemType1 itemType1)
    {
        return getSomeUseful() == itemType1.getSomeUseful();
    }

关于java - 如果在验证规则中使用类型代码,如何进行重构以消除类型代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28204492/

相关文章:

java - 接收安卓短信

java - 如何从 ContainerRequestContext 获取路径参数

java - java中如何读取大于127的字节?

php - 如何使唯一数组的自定义验证规则依赖于其他字段 laravel

design-patterns - 开发人员在编码时主要关注什么?

Java:实现一个新线程,现在我的代码执行了两次

PHP验证灵活有效的URI

ruby-on-rails - Rails 验证对象中的所有属性

java - Java 中的多重继承 - Spring Data

java - 模式 "Visitor"还是动态转换?