Return-Path: X-Original-To: apmail-commons-dev-archive@www.apache.org Delivered-To: apmail-commons-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id DA046F12F for ; Wed, 1 May 2013 18:27:57 +0000 (UTC) Received: (qmail 42921 invoked by uid 500); 1 May 2013 18:27:57 -0000 Delivered-To: apmail-commons-dev-archive@commons.apache.org Received: (qmail 42764 invoked by uid 500); 1 May 2013 18:27:57 -0000 Mailing-List: contact dev-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Commons Developers List" Delivered-To: mailing list dev@commons.apache.org Received: (qmail 42753 invoked by uid 99); 1 May 2013 18:27:57 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 01 May 2013 18:27:57 +0000 X-ASF-Spam-Status: No, hits=0.0 required=5.0 tests= X-Spam-Check-By: apache.org Received-SPF: error (athena.apache.org: local policy) Received: from [80.67.169.19] (HELO solo.fdn.fr) (80.67.169.19) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 01 May 2013 18:27:50 +0000 Received: from lehrin.spaceroots.org (smtp.spaceroots.org [80.67.176.229]) by smtp.fdn.fr (Postfix) with ESMTP id 425B74475A for ; Wed, 1 May 2013 20:27:07 +0200 (CEST) Received: from [127.0.0.1] (lehrin.spaceroots.org [127.0.0.1]) by lehrin.spaceroots.org (Postfix) with ESMTP id 8ECB05F581 for ; Wed, 1 May 2013 20:27:06 +0200 (CEST) Message-ID: <51815E7A.9000702@free.fr> Date: Wed, 01 May 2013 20:27:06 +0200 From: Luc Maisonobe User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.12) Gecko/20130116 Icedove/10.0.12 MIME-Version: 1.0 To: Commons Developers List Subject: Re: [math] fluent/builder API for algorithms in 4.0 ? References: <517EA294.8030606@spaceroots.org> <5180E349.8070101@free.fr> <2c8736a653a31c0950d14443c7dd6ae6@scarlet.be> In-Reply-To: <2c8736a653a31c0950d14443c7dd6ae6@scarlet.be> X-Enigmail-Version: 1.4.1 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Virus-Checked: Checked by ClamAV on apache.org Le 01/05/2013 17:53, Gilles a écrit : >> [...] >> One of the pitfalls or devil in the details we can expect is we attempt >> to do this while still having a class hierarchy for some aspects, >> typically with an abstract class at the top. >> >> Lets consider a withMaxEvaluation(int maxEval) implementation which may >> probably be implemented once in the abstract class and simply inherited >> in the specialized classes deeper in the hierarchy. >> >> The top implementation should create an object of the appropriate type. >> The simplest solution I think of is having a protected factory method. >> So if we look at the abstract class and one of its derived class, we >> should have something like: >> >> public abstract class AbstractAlgorithm { >> >> private final int maxEval; >> >> protected AbstractAlgorithm(final int maxEval) { >> this.maxEval = maxEval; >> } >> >> public AbstractAlgorithm() { >> // default setting >> this(Integer.MAX_VALUE); >> } >> >> protected abstract AbstractAlgorithm build(final int maxEval); >> >> public AbstractAlgorithm withMaxEval(final int maxEval) { >> return build(maxEval); >> } >> >> public int getMaxEval() { >> return maxEval; >> } >> >> } >> >> public class SpecializedAlgorithm >> extends AbstractAlgorithm implements ThresholdTunable { >> >> private final double threshold; >> >> protected SpecializedAlgorithm(final int maxEval, >> final double threshold) { >> super(maxEval); >> this.threshold = threshold; >> } >> >> public SpecializedAlgorithm() { >> // use default values all way up to the class root >> super(); >> this.threshold = 1.0; >> } >> >> protected SpecializedAlgorithm build(final int maxEval) { >> // make sure we don't lose our local threshold >> // when the top level abstract class creates a new instance >> // with an updated maxEval >> return new SpecializedAlgorithm(maxEval, threshold); >> } >> >> public SpecializedAlgorithm withThreshold(final double threshold) { >> return new SpecializedAlgorithm(getMaxEval(), threshold); >> } >> >> } >> > > From what you proposed in the original post, I rather understood > the following: > > public abstract class AbstractAlgorithm { > private final int maxEval; > > protected AbstractAlgorithm(final int maxEval) { > this.maxEval = maxEval; > } > > public int getMaxEval() { > return maxEval; > } > } > > public class SpecializedAlgorithm > extends AbstractAlgorithm > implements ThresholdTunable, > IterationLimitable { > private final double threshold; > > protected SpecializedAlgorithm(final int maxEval, > final double threshold) { > super(maxEval); > this.threshold = threshold; > } > > public SpecializedAlgorithm() { > this(Integer.MAX_VALUE); > } > > public double getThreshold() { > return threshold; > } > > public SpecializedAlgorithm withThreshold(final double threshold) { > return new SpecializedAlgorithm(getMaxEval(), threshold); > } > > public SpecializedAlgorithm withMaxEval(int maxEval) { > return new SpecializedAlgorithm(maxEval, getThreshold()); > } > } > > I.e. the "end-user" instantiates using the default constructor and applying > "withXxx" methods. > All classes in the hierarchy provide "protected" constructors to allow > subclasses to set the state implemented in the base classes. > > Is there something wrong with that approach? No, I even think it is a better way. The post just above correspond to the case when we still have some remains of a hierarchy and some code that is handled at top level (here in the abstract class). If all withXxx methods are implemented at bottom level, it is simpler, as you suggest. Luc > > > Gilles > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org > For additional commands, e-mail: dev-help@commons.apache.org > > --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org For additional commands, e-mail: dev-help@commons.apache.org