Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如果在验证规则中使用类型代码,如何进行重构以消除类型代码?_Java_Validation_Design Patterns_Refactoring - Fatal编程技术网

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

Java 如果在验证规则中使用类型代码,如何进行重构以消除类型代码?,java,validation,design-patterns,refactoring,Java,Validation,Design Patterns,Refactoring,假设在集合中添加新元素之前,我们必须检查一些规则集。元素是一些类似类型的对象。所有特定于类型的特性都封装在抽象类的子类中。集合包含此抽象类的对象。这些规则为类型应用条件以及其他约束。因此,items的抽象超类具有额外的类型代码。新元素可以添加到集合中,但由于其他规则,集合中的其他元素可以删除或替换 在需要重构的代码中,规则的验证被实现为一个长代码块,其中包含嵌套的控制流语句。类型代码的验证会破坏封装。控制流语句的单独分支不能定义为集合元素的相应子类的方法,因为它们需要检查类型并对集合进行更改 关

假设在集合中添加新元素之前,我们必须检查一些规则集。元素是一些类似类型的对象。所有特定于类型的特性都封装在抽象类的子类中。集合包含此抽象类的对象。这些规则为类型应用条件以及其他约束。因此,items的抽象超类具有额外的类型代码。新元素可以添加到集合中,但由于其他规则,集合中的其他元素可以删除或替换

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

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

  • 类型代码不影响类的行为
  • 类型代码是不可变的
  • ItemsManager使用类型代码在添加之前解析某些规则 将新元素添加到集合中
如何消除类型代码并将规则与类型分开

以下是此类问题的示例:

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

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

抽象类AbstractItem{
private int Type;//这将消除
私人投资是有用的;
受保护的抽象项(int类型,int值){
this.Type=Type;
this.someusiver=值;
}
public int getType(){返回this.Type;}
public int getsomeusuble(){返回this.someusuble;}
@凌驾
公共字符串toString(){
返回String.format(“项{Type=%d,Value=%d}”,类型,someusiver);
}
}
类ItemType1扩展了AbstractItem{
ItemType1(int值){super(1,Value);}
}
类ItemType2扩展了AbstractItem{
ItemType2(int值){super(2,Value);}
}
类项目管理器{
私有java.util.ArrayList ListoItems;
公共项目经理(){
this.ListOfItems=new java.util.ArrayList();
}
公共作废添加(最终摘要项newItem){
//这段代码破坏了封装
开关(newItem.getType()){
案例1:
//执行一些类型相关的操作
for(AbstractItem i:this.ListOfItems){
如果(i.getType()==2&&i.getSomeUsage()==newItem.getSomeUsage()){
本.ListOfItems.remove(i);
打破
}
}
打破
案例2:
//执行其他类型相关的操作
打破
违约:
//抛出错误
}
this.ListOfItems.add(newItem);
}
@凌驾
公共字符串toString(){
String str=String.format(“ItemsManager内容”);
for(AbstractItem i:this.ListOfItems){
str+=String.format(“\n\t类型=%d,值=%d”,i.getType(),i.getSomeUsable());
}
返回str;
}
}
公共课示例1{
公共静态void main(字符串[]arg){
System.out.println(“示例1”);
ItemManager im=新的ItemManager();
im.添加(新项目类型1(1));
im.添加(新项目类型2(2));
im.添加(新项目类型2(3));
im.添加(新项目类型1(3));
System.out.println(im.toString());
}
}
/*
例1
ItemsManager内容
类型=1,值=1
类型=2,值=2
类型=1,值=3
*/

这并不理想,但这是实现某种封装和终止switch语句的一步

将onAdd方法添加到将列表作为参数的基类中

 public java.util.ArrayList<AbstractItem> onAdd(java.util.ArrayList<AbstractItem> list) { return list; }

从@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;
}
在类型2子类中重写

    @Override
    public boolean shoudBeRemovedBecauseType1(ItemType1 itemType1)
    {
        return getSomeUseful() == itemType1.getSomeUseful();
    }
@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;
    }
    @Override
    public boolean shoudBeRemovedBecauseType1(ItemType1 itemType1)
    {
        return getSomeUseful() == itemType1.getSomeUseful();
    }