Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / First Aid / December 2005

Tip: Looking for answers? Try searching our database.

Constructor Conundrum

Thread view: 
Lash Rambo - 28 Dec 2005 02:04 GMT
Say I have two class hierarchies--Problem and Solver--which sketch like
this:

public abstract class AbstractProblem {
       private AbstractSolver _solver;

       // ...
}

public class ConcreteProblem extends AbstractProblem {
       // ...
}

public abstract class AbstractSolver {
       public void solve(/* ... */) {
              // ...
       }

       // ...
}

public class ConcreteSolver extends AbstractSolver {
       // lots of parameters not in AbstractSolver

       // ...
}

ConcreteProblem needs to create a ConcreteSolver and hand it over to
AbstractProblem.  The catch is: ConcreteSolver has several parameters
(variables controlling ConcreteProblem's behavior) ConcreteProblem may
want to change from their default values.  Changing parameters is
accomplished through accessors.

How can I do this?  I've tried...

public abstract class AbstractProblem {
       private AbstractSolver _solver;

       public AbstractProblem(AbstractSolver solver) {
              _solver = solver;
       }

       // ...
}

public class ConcreteProblem extends AbstractProblem {
       ConcreteSolver _cs = new ConcreteSolver();

       public ConcreteProblem() {
              super(_cs);
              _cs.setParam(/* ... */);
       }

       // ...
}

...but Java won't let me access _cs before AbstractProblem's constructor
has been called.

I'd prefer to keep AbstractProblem's _solver private, since I can't give
subclasses access to it without giving everything else in the package
access to it, which I don't want to do.  (Although I guess I could put
the Problem and Solver hierarchies into separate packages with nothing
else in them to approximate subtype-but-not-package access.)

I can't make all of ConcreteSolver's parameters settable via its
constructor, because I may want to change some defaults without changing
others, which I can't always do since Java lacks named parameters (as far
as I know).

Any ideas?
VisionSet - 28 Dec 2005 11:48 GMT
> Say I have two class hierarchies--Problem and Solver--which sketch like
> this:

Can you provide a simple *compilable* example that illustrates the problem?

--
Mike W
PetriSchmitz - 28 Dec 2005 20:26 GMT
Hi Lash,

I suggest to use a factory method:

public class ConcreteProblem extends AbstractProblem {
        //ConcreteSolver _cs = new ConcreteSolver(); // obsolent, see
factory-meth.

        public ConcreteProblem(ConcreteSolver _cs) { // perhabs change to
private
               super(_cs);
               _cs.setParam(/* ... */);
        }

        public static ConcreteProblem getInstance () {
              ConcreteSolver _cs = new ConcreteSolver();
              return new ConcreteProblem (_cs);
       }
}

So you have encapsulated the constructor and seperated the creation of
ConcreteSolver from the creation of ConcreteProblem.
Perhabs you better use superclasses instead of concretes, e.g.

        public ConcreteProblem(AbstractSolver _cs)

instead of

        public ConcreteProblem(ConcreteSolver _cs) {

or

       AbstractSolver _cs = new ConcreteSolver();

instead of

       ConcreteSolver _cs = new ConcreteSolver();

I hope my sugesstions were helpful to you.

Greetz, Peter

> Say I have two class hierarchies--Problem and Solver--which sketch like
> this:
[quoted text clipped - 67 lines]
>
> Any ideas?
PetriSchmitz - 28 Dec 2005 20:33 GMT
SUPPLEMENTAL:

if you need _cs as an instance variable then the class down here is
much more appropriate:

public class ConcreteProblem extends AbstractProblem {
         ConcreteSolver _cs;

         public ConcreteProblem(ConcreteSolver _cs) { // perhabs change
to
private
                super(_cs);
               this._cs = _cs
                _cs.setParam(/* ... */);
         }

         public static ConcreteProblem getInstance () {
               ConcreteSolver _cs = new ConcreteSolver();
               return new ConcreteProblem (_cs);
        }
 }
ricky.clarkson@gmail.com - 29 Dec 2005 05:07 GMT
interface Problem
{
  void visit(ProblemVisitor visitor);
}

interface Solution
{
  void solve(Problem problem);
}

final class WantToExitProblem implements Problem
{
  void visit(final ProblemVisitor visitor)
  {
     visitor.accept(this);
  }
}

final class WantToExitSolution implements Solution
{
  public void solve(final Problem problem)
  {
     final WantToExitChecker checker=new WantToExitChecker();
     problem.visit(checker);

    if (checker.hasWantToExit())
        System.exit(0);
  }
}

interface ProblemVisitor
{
  void accept(WantToExitProblem problem);
}

final class WantToExitChecker implements Visitor
{
  private boolean hasWantToExit;

  public void accept(final WantToExitProblem problem)
  {
     hasWantToExit=true;
  }

  public boolean hasWantToExit()
  {
     return hasWantToExit;
  }
}
Lash Rambo - 29 Dec 2005 19:19 GMT
> Hi Lash,
>
[quoted text clipped - 17 lines]
>         }
>  }

The only consequence I see of the above version, compared to my original
version, is that now, instead of saying

ConcreteProblem cp = new ConcreteProblem();

I say

ConcreteProblem cp = ConcreteProblem.getInstance();

.

I toyed with factory methods a little more, but can't figure out a way to
get an abstract superclass' constructor to use its concrete subclass'
factory method, while at the same time keeping things private.  Maybe it
could be done via reflection, but so too could a child's sandcastle be
sieged with a full-sized trebuchet.  :)

> So you have encapsulated the constructor and seperated the creation of
> ConcreteSolver from the creation of ConcreteProblem.

I'm not sure what you mean.  In the version above, ConcreteProblem cannot
be instantiated without instantiating a ConcreteSolver, so their creation
seems very much not separate.

Anyway, I settled on tighter packaging and using "protected".  I'm not
100% happy with the solution, but it's the best balance of simplicity and
security I could come up with.  (Plus, the project is now better
organized.)


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.