如何与任何一个班级分享自我回归的方法链?

时间:2013-12-31 01:59:25

标签: java method-chaining

更新:我明白了!事实证明,鲍里斯蜘蛛的“GENERICS”评论正是我所需要的线索。

原始问题和破碎的代码首先,解决方案如下。我的通用设计需要下面的needer。

原始问题和非工作代码

在过去的几年中,我一直试图让自我回归的方法链与其他类“共享”。这是为了避免必须复制每个子类中的每个自返回函数的巨大痛苦。基本思想是将“needer”类传递给“needable”类以开始配置,然后在配置结束时将needer传递回去。 “required”对象在内部设置。

例如:

ConfigUser cu = (new ConfigUser()).
   cfgFavNum().twentySeven().increment().timesTwo().endCfg().
   firstName("Kermit").lastName("Frog");

,其中

firstName("Kermit").lastName("Frog")

是ConfigUser类的一部分,

twentySeven().increment().timesTwo().endCfg()

来自单独的“配置数字”类。 endCfg()返回“needer”类(ConfigUser),此时应该能够在ConfigUser中继续链接。但你不能。在下面的代码中......在我所做的每一次尝试中,我最终都得到了同样的错误:

        C:\java\ConfigUser.java:4: cannot find symbol
        symbol  : method firstName(java.lang.String)
        location: interface NeedsFavNum
                 cfgFavNum().twentySeven().increment().timesTwo().endCfg().
                                                                          ^

如果您在endCfg()之后注释掉所有内容,则会显示问题:

ConfigUser cu = (new ConfigUser()).
   cfgFavNum().twentySeven().increment().timesTwo().endCfg();//.
   //firstName("Kermit").lastName("Frog");

         C:\java\ConfigUser.java:15: incompatible types
         found   : NeedsFavNum
         required: ConfigUser
                        cfgFavNum().twentySeven().increment().timesTwo().endCfg();//.
                                                                               ^

它不能返回ConfigUser,它是 NeedsFavNum的子类,它是所有类“需要”favorite-number-config的接口。

当然,您可以复制所有函数,以便它们返回ConfigUser - s,但这会破坏共享链的目的。目的是在任何类中共享这些链,而不仅仅是子类。

有没有办法实现这一目标,或重新思考整个问题?我开始认为这根本不可能。

详细信息如下代码所示。它的工作原理(......无论如何都是这些编译错误):将它复制到一个名为ConfigUser.java的文件中并尝试一下。

感谢您帮助我。

public class ConfigUser implements NeedsFavNum  {
   public static final void main(String[] igno_red)  {
      ConfigUser cu = (new ConfigUser()).
         cfgFavNum().twentySeven().increment().timesTwo().endCfg().
         firstName("Kermit").lastName("Frog");

      cu = (new ConfigUser()).                  cfgFavNum().twentySeven().increment().timesTwo().endCfg();//.
      //         firstName("Kermit").lastName("Frog");
   }
//init
   public static final int iDEFAULT_FAV = 8;
   int iFav = -1;
   String sName1st = null;
   String sNameLast = null;
//funcs
   public ConfigUser()  {
   }
   public ConfigUser firstName(String s_s)  {
      sName1st = s_s;
   }
   public ConfigUser lastName(String s_s)  {
      sNameLast = s_s;
   }
   public FavNumConfigurator cfgFavNum()  {
      return  new FavNumConfigurator(this, iDEFAULT_FAV);
   }
   public ConfigUser setNumReturnNeeder(int i_favFullyConfigured)  {
      iFav = i_favFullyConfigured;
      return  this;
   }
}
interface NeedsFavNum  {
   ConfigUser setNumReturnNeeder(int i_fav);
}
class FavNumConfigurator  {
   NeedsFavNum nfn = null;
   int iFav = -1;
   public FavNumConfigurator(NeedsFavNum nf_n, int i_defaultFav)  {
      nfn = nf_n;
      iFav = i_defaultFav;
   }
   public FavNumConfigurator twentySeven()  {
      iFav = 27;
   }
   public FavNumConfigurator timesTwo()  {
      iFav = iFav * 2;
   }
   public FavNumConfigurator increment()  {
      iFav += 1;
   }
   public NeedsFavNum endCfg()  {
      return  nfn.setNumReturnNeeder(iFav);
   }
}

具有工作代码的解决方案

事实证明,鲍里斯蜘蛛的“GENERICS”评论正是我所需要的线索。而不是“需要的”类

FavNumConfigurator

现在它的

FavNumConfigurator<R extends FavNumNeeder>

其中FavNumNeeder是需要favorite-number配置链的任何类的“needer”接口。现在endCfg()函数可以返回我想要的类。

这是固定的例子(它可以工作 - 复制并保存为ConfigUser.java):

/**
   <P>The main class: the &quot;needer&quot;.</P>
 **/
public class ConfigUser implements NeedsFavNum  {
   public static final void main(String[] igno_red)  {
      ConfigUser cu = (new ConfigUser()).
         cfgFavNum().twentySeven().increment().timesTwo().timesTwo().endCfg().
         firstName("Kermit").lastName("Frog");

      System.out.println("name:         " + cu.sName1st + " " + cu.sNameLast);
      System.out.println("favorite-num: " + cu.iFav);

      //---OUTPUT:
      //name:         Kermit Frog
      //favorite-num: 112
   }
//init
   public static final int iDEFAULT_FAV = 8;
   int iFav = -1;
   String sName1st = null;
   String sNameLast = null;
//funcs
   public ConfigUser()  {
   }
   //Self-returning configurers...START
      public ConfigUser firstName(String s_s)  {
         sName1st = s_s;
         return  this;
      }
      public ConfigUser lastName(String s_s)  {
         sNameLast = s_s;
         return  this;
      }
   //Self-returning configurers...END
   //Start fav-num configuration. Returns the "needable"
   public FavNumConfigurator<ConfigUser> cfgFavNum()  {
      return  (new FavNumConfigurator<ConfigUser>(this, iDEFAULT_FAV));
   }
   //Called by the "needable" in endCfg()
   public ConfigUser setNumReturnNeeder(int i_favFullyConfigured)  {
      iFav = i_favFullyConfigured;
      return  this;
   }
}

//The "needer" interface, for all classes needing favorite-number
//configuration
interface NeedsFavNum  {
   ConfigUser setNumReturnNeeder(int i_fav);
}

//The "needable" class: A shareable function-chain for favorite-number
class FavNumConfigurator<R extends NeedsFavNum>  {
   R nfn = null;
   int iFav = -1;
   public FavNumConfigurator(R nf_n, int i_defaultFav)  {
      nfn = nf_n;
      iFav = i_defaultFav;
   }
   //Self-returning configurers...START
      public FavNumConfigurator<R> twentySeven()  {
         iFav = 27;
         return  this;
      }
      public FavNumConfigurator<R> timesTwo()  {
         iFav = iFav * 2;
         return  this;
      }
      public FavNumConfigurator<R> increment()  {
         iFav += 1;
         return  this;
      }
   //Self-returning configurers...END
   public R endCfg()  {
      nfn.setNumReturnNeeder(iFav);
      return  nfn;
   }
}

通用的needer-needable设计

这是我设计的通用needer-needable解决方案,它实现了上述修复。最难的部分是避免ConfigNeedableConfigNeeder之间的循环依赖。

public interface Chainable  {
   Chainable chainID(Object o_id);
   Object getChainID();
}
public interface ConfigNeedable<O,R extends ConfigNeeder> extends Chainable  {
   boolean isAvailableToNeeder();
   ConfigNeedable<O,R> startConfigReturnNeedable(R c_n);
   R getActiveNeeder();
   boolean isNeededUsable();
   R endCfg();
}
public interface ConfigNeeder  {
   void startConfig();
   boolean isConfigActive();
   <O> Class<O> getNeededType();
   <O> void setNeeded(O o_fullyConfigured);
}

以下是使用此设计的相同(工作)示例,但由于它依赖于我个人库中的实现(目前尚未发布,因为它在我工作时会逐渐变化),不会编译。希望它能帮助别人看到。

import  xbn.lang.chain.ChainableComposer;
import  xbn.lang.chain.ConfigNeeder;
import  xbn.lang.chain.SimpleConfigNeedable;
import  xbn.lang.chain.SimpleConfigNeeder;

public class ConfigNeedableNeederXmpl  {
   public static final void main(String[] igno_red)  {
      UserSettings us = (new UserSettings()).
         cfgFavInt().twentySeven().timesTwo().increment().endCfg().name("President Obama");
      System.out.println("name=" + us.sName);
      System.out.println("favorite number=" + us.iFav);
   }
}
class UserSettings implements ConfigNeeder  {
   private SimpleConfigNeeder scn = new SimpleConfigNeeder(Integer.class);
   public static final int iDEFAULT_FAV = 8;
   public int iFav = -1;
   public String sName = null;

   public UserSettings name(String s_name)  {
      sName = s_name;
      return  this;
   }
   public FavNumConfigurator cfgFavInt()  {
      FavNumConfigurator fnc = new FavNumConfigurator();
      fnc.startConfigReturnNeedable(this);
      return  fnc;
   }
   //ConfigNeeder: composition implementation...START
      public <O> void setNeeded(O i_fullyConfigured)  {
         scn.setNeeded(i_fullyConfigured);
         iFav = (Integer)scn.getElimNeeded();
      }
      public void startConfig()  {
         scn.startConfig();
      }
      public boolean isConfigActive()  {
         return  scn.isConfigActive();
      }
      public <O> Class<O> getNeededType()  {
         return  scn.getNeededType();
      }
      public void endConfig()  {
         iFav = (Integer)scn.getElimNeeded();
      }
   //ConfigNeeder: composition implementation...END
}
class FavNumConfigurator extends SimpleConfigNeedable<Integer,UserSettings>  {
   public FavNumConfigurator()  {
      super(33, true);
   }
   public FavNumConfigurator(Integer o_defaultNeeded, boolean b_defaultNeededUsable)  {
      super(o_defaultNeeded, b_defaultNeededUsable);
   }
   public FavNumConfigurator set(int i_i)  {
      try  {
         updateObject(i_i);
      }  catch(RuntimeException rtx)  {
         throw  newRTXWChainID("set", rtx);
      }
      return  this;
   }
   public FavNumConfigurator twentySeven()  {
      updateObject(27);
      return  this;
   }
   public FavNumConfigurator timesTwo()  {
      updateObject(getNeededInProcess() * 2);
      return  this;
   }
   public FavNumConfigurator increment()  {
      updateObject(getNeededInProcess() + 1);
      return  this;
   }
}

1 个答案:

答案 0 :(得分:1)

您正在寻找的是C ++ Curiously recurring template pattern

您可以将所有“共享”自返回位放在基本抽象类中,然后对其进行扩展。

例如:

public abstract class Base<T extends Base<T>>
{
   protected abstract T self(); 

   protected String name;
   protected String address;

   public T withtName(String name)
   {
       this.name = name;
       return self();
    }

   public T withAddress(String address)
   {
       this.address = address;
       return self();
   }

}

class MyClass extends Base<MyClass>
{
    private String someOtherThing;

    public MyClass withSomeOtherThing(String thing)
    {
        this.someOtherThing = thing;
        return self();
    }

    @Override
    protected MyClass self()
    {
        return this;
    }    
 }

现在你可以做到:

MyClass mc = 
    new MyClass()
        .withAddress("111 elm")
        .withtName("Bob")
        .withSomeOtherThing("foo");