a class refactoring problem.

R

Roedy Green

Let us say you wanted to end up with a class structure something like
this:

class Core : contains data fields and intelligent accessors and
virtual fields.

Stage1 extends Core

Stage2 extends Core

Stage3 extends Core

Stage1 Stage2 and Stage3 have nothing whatsoever to do with each
other.

Then you create a Core object and somehow invoke:

Stage1.doEverithing()
Stage2.doEverything();
Stage3.doEverything();

on your Core object.

Let us presume you have everything in one giant Core class now where
all the code is this.based.

In my particular case, long ago I have a similar problem where
refactored it like this:

Stage1 extends Core
Stage2 extends Stage1
Stage3 extends Stage2

This turned out to confusing, creating too many "adhesions" between
Stage1 Stage2 and Stage3. The compiler did not help enforce placement
of Stage3 code purely in class Stage3.

It looks as if I will need to pass a delegate Core object to Stage1,
Stage2 and Stage3. It then must do one of two things that I am
reluctant to do

1. have each Stage extend Core, and then in a copy-constructor copy
the values of all the individual fields to this.xxx (a maintenance
and debugging nightmare.) Java has no facility for creating code for a
copy constructor for the Dog Field to converta Dog to a Dalmatian,
even though in assembler it is just a single instruction.

2. use a delegate object. This means changing every reference to every
field in the entire code body.

Can you think of lower-labour approach?

--
Roedy Green Canadian Mind Products
http://mindprod.com

"Species evolve exactly as if they were adapting as best they could to a changing world, and not at all as if they were moving toward a set goal."
~ George Gaylord Simpson
 
R

Roedy Green

Perhaps you could explain how you are supposed to be able to invoke three
different methods on three different unrelated classes extending the type
of the instance you did create. Are these to be static methods? If so,
why is the base type relevant at all? If they are not, how do you get
from the base type instance to the sub-class methods?


Perhaps if I explained my particular case it would come clear. I
though it would just cloud the issue and distract it from the point I
am trying to make. It is probably best to talk about the actual
problem since it may have solutions outside the box of the artificial
example.


I have a number of facts about a computer package I have written. The
is a ton of stuff, much of it deduced from the basic facts e.g
name of the project, main class files, is it an Applet, does it use
JNI, it is signed, what languages are used...

I then do various things with this basic core of data e.g.

generate ant scripts to build /and or bundle a distribution zip,
create aux files, check consistency with the prices database,
create duplicates of various files, ensure various files are present
and the version, release dates, file sizes etc are consistent in
source code, docs, PADs etc, and in some cases patch files to make
them consistent.

The generating of a 4NT/Take Command DESCRIBE file to annotate all the
files with their names has nothing at all to do with the generating of
an ant build script, except that they use the common bank of core
project data.

On my most recent refactoring binge, I ended up refactoring it with a
copy constructor in Core, with Stage1, Stage2 and Stage3 each
extending the basic Core class of data.

the Stage1 constructor takes a Core object. It passes it to the Core
constructor that extracts the crucial data out of it, and regenerates
the Core fields, rather that copying all the inferred data out of the
Core object parameter, field by field. In this case the overhead is
completely acceptable, though in general, I don't like it. You SHOULD
be able to just set up the Core field in your extended Stage1 object
with a code that generates a single move bytes instruction, the way an
assembler programmer would do it.

I pull the whole thing together like this:


class StompOneProject() extends ProjectInfo
{
....


/**
* do everything for this project, generate all files
*/
void stomp()
{
ceateProjectDirectory();
new SanityCheckProject( this ).stomp();
deleteObsoletes();
new MkAuxFiles( this ).stomp();
new FixPads( this ).stomp();
new MkAnt( this ).stomp();
new MkDesc( this ).stomp();
new CrossCheckProject( this ).stomp();
}

Where "this" is an extended ProjectInfo/Core object.

Each of the other classes has a stomp Method does whatever that class
does to a project.

Stomp could an abstract method of ProjectInfo, part of an interface,
or an arbirary name. The code would work just as well is if it had
been written. There is no pressing reasons all the classes had to have
a stomp method. It was just a way of naming a hierarchy of work.


/**
* do everything for this project, generate all files
*/
void stomp()
{
ceateProjectDirectory();
new SanityCheckProject( this ).checkSanity();
deleteObsoletes();
new MkAuxFiles( this ).generateMiscFiles();
new FixPads( this ).PatchPADfiles();
new MkAnt( this ).generateAntScripts();
new MkDesc( this ).buildFileDecriptions();
new CrossCheckProject( this ).crossCheckForConsistency();
}


If you want to see the actual code, have a look at the Subversion
repository. You can view it with an ordinary browser. This is not code
I distribute. It for my personal use.

https://wush.net/websvn/mindprod/listing.php?repname=mindprod&path=/com/mindprod/stomp/
--
Roedy Green Canadian Mind Products
http://mindprod.com

"Species evolve exactly as if they were adapting as best they could to a changing world, and not at all as if they were moving toward a set goal."
~ George Gaylord Simpson
 
M

Mark Space

Roedy said:
1. have each Stage extend Core, and then in a copy-constructor copy
the values of all the individual fields to this.xxx (a maintenance
and debugging nightmare.) Java has no facility for creating code for a
copy constructor for the Dog Field to converta Dog to a Dalmatian,


Would clone() help here?

class Core implements Clonable
{
....

protected Core clone() // just a sketch, needs full clone() pattern
{
Core c = (Core) super.clone();
// more stuff?
return c;
}
}

I wonder if you could use this in the copy constructors.

class Stage1 extends Core
{
public Stage2 stage2()
{
Core c = super.clone();
// turn this into stage2 somehow...
return new Stage2( c );
}
}

I'm not seeing the full pattern here but this might save you some
maintenance hassle so you don't have to copy each field manually.
 
M

Mark Space

Roedy said:
The generating of a 4NT/Take Command DESCRIBE file to annotate all the
files with their names has nothing at all to do with the generating of
an ant build script, except that they use the common bank of core
project data.


I'm weirdly reminded of the Visitor Pattern here, possibly because it
just game up recently in another thread. But you have a hierarchy of
objects, that you want to preform various operations on. The operations
have nothing in common except they work with the hierarchy of objects.

Hmmm....

Note the gang-of-four considers the Visitor to be a bad idea if you
frequently add new objects in the hierarchy. It's better if the
hierarchy stays as is, and you mostly just add new visitors as you come
up with new things to do.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top