Splitting an inherited class to share across teams

C

Codex Twin

Hi

I have a common model for a Data Access Layer scenario. I have an abstract
base class, called DalBase which contains a list of abstract methods. Lets
call them:
public abstract void Shine();
public abstract void Flow();
public abstract void Float();

I then have an inherited class, called DalMain which contains the concrete
implementations of these methods

DalMain : DalBase
{
public override void Shine()
{
...
}

public override void Flow()
{
...
}

public override void Float()
{
...
}
}

I have a third class, DataAccessBaseClass, which has a static method called
GetDalLayer() which checks that the type of DalMain is DalBase, and if it
is, returns the type of the DalMain class. The beauty of this is, if I need
to call Flow() in a business class, all I need to do is:

DalBase dal = DataAccessBaseClass.GetDalLayer();
//dal is now of type DalMain
dal.Flow();

and this will call the Flow() in the DalMain class. All nice and good!

However, I am in a team environment, and I have a 100+ abstract methods in
DalBase. Which means that DalMain is in constant demand and causing a
development bottleneck.

I want to split up DalMain into separate "responsible" classes, so as to
share out the functionality and place less of a burden on the editing of the
DalMain class by the entire team.

What do I need to do to retain the same mode of invoking the DalBase
methods, but from concrete implementations in these classes:

public class Moon
{
public override void Shine()
{
...
}
}

public class Liquid
{
public override void Flow()
{
...
}
}

public class Balloon
{
public override void Float()
{
...
}
}

I want to be able to call the Flow() method

DalBase dal = DataAccessBaseClass.GetDalLayer();
dal.Flow();

and this will call the Flow() in the Liquid class - which now has the
implentation for Flow(). And the same for the other methods in the Moon and
Balloon classes.

What should I do?
 
J

Jon Skeet [C# MVP]

However, I am in a team environment, and I have a 100+ abstract methods in
DalBase. Which means that DalMain is in constant demand and causing a
development bottleneck.

I want to split up DalMain into separate "responsible" classes, so as to
share out the functionality and place less of a burden on the editing of the
DalMain class by the entire team.

A couple of possibilities:

1) Don't have a single base class in the first place - split it into
several. This sounds like it would be a good idea anyway.

2) Change DalBase to several interfaces, and have a proxy class which
implements all the interfaces. Split DalMain into several smaller
classes, each implementing a single interface. The proxy class would
create an instance of each of the smaller classes, and forward the
method calls for each interface to the appropriate implementation.
 
C

Codex Twin

Jon Skeet said:
A couple of possibilities:
1) Don't have a single base class in the first place - split it into
several. This sounds like it would be a good idea anyway.

2) Change DalBase to several interfaces, and have a proxy class which
implements all the interfaces. Split DalMain into several smaller
classes, each implementing a single interface. The proxy class would
create an instance of each of the smaller classes, and forward the
method calls for each interface to the appropriate implementation.



Jon

Thanks! I really like the sound of the second idea you've explained.

From my reading of your solution and the Proxy design pattern (which I
looked up), this is my understanding of your suggestion:



1) The DalBase class is changed to smaller interfaces:

IDalBalloon and IDalLiquid

They contain definitions for Float() and Flow() respectively.



2) Split DalMain into smaller classes each implementing a smaller interface:



// Balloon - now contains a concrete implementation of Float()

public class Balloon : IDalBalloon

{

public void Float()

{.}

}



//Liquid - now contains a concrete implementation of Flow()

public class Liquid : IDalLiquid

{

public void Flow()

{.}

}



3) Have one proxy which implements all the interface and creates an instance
of the individual classes:

public class DalProxy : IDalBalloon, IDalLiquid

{

//Members

//some form of instantiation

Balloon balloon = new Balloon();

//cast to IDalBalloon to check if it is an IDalBalloon

IDalBalloon isBalloon = balloon as IDalBalloon;



Liquid liquid = new Liquid();

//cast to IDalLiquid to check if it is an IDalLiquid

IDalLiquid isLiquid = liquid as IDalLiquid;



Public void Float()

{

if (isBalloon != null)

isBalloon.Float();

else

throw new Exception("Balloon must
implement IDalBalloon");

}



Public void Flow()

{

if (iLiquid != null)

isLiquid.Flow();

else

throw new Exception("Liquid must
implement IDalLiquid");

}

}





4) Then in a client.

DalProxy p = new DalProxy;

//invoke Flow()

p.Flow();

//invoke Float()

p.Float();





This solves the first of my two problems: that of having a logical layer of
classes which do all the concrete implementation and have to be
interchangeable. In other words I can now have a library of SQL classes:
(SqlBalloon implementing IDalBalloon) and an alternative library of Oracle
classes (OracleBalloon implementing IDalBalloon).



However, using one single Proxy class (DalProxy) for invoking the methods
would present the same problem of having one DalMain, that I faced in my
solution. It means that the development bottleneck of having the team lining
up to edit DalProxy would still be there!

But the good thing is, I can have a number of specialist Proxy classes,
DalBalloonProxy and DalLiquidProxy which each implements the IDalBalloon and
IDalLiquid interfaces respectively, and each is responsible to their methods
specifically.



Thanks again.
 
C

Codex Twin

Reposted, with improved formatting.

Jon Skeet said:
A couple of possibilities:

1) Don't have a single base class in the first place - split it into
several. This sounds like it would be a good idea anyway.

2) Change DalBase to several interfaces, and have a proxy class which
implements all the interfaces. Split DalMain into several smaller
classes, each implementing a single interface. The proxy class would
create an instance of each of the smaller classes, and forward the
method calls for each interface to the appropriate implementation.

Jon
I really like the sound of the second idea you have explained above.
From my reading of your solution and the Proxy design pattern (which I
looked up), this is my understanding of your suggestion:

1) The DalBase class is changed to smaller interfaces:
IDalBalloon and IDalLiquid
They contain definitions for Float() and Flow() respectively.

2) Split DalMain into smaller classes each implementing a smaller interface:

// Balloon - now contains a concrete implementation of Float()
public class Balloon : IDalBalloon
{
public void Float()
{.}
}

// now contains a concrete implementation of Flow()
public class Liquid : IDalLiquid
{
public void Flow()
{.}
}

3) Have one proxy which implements all the interface and creates an instance
of the smaller classes:
public class DalProxy : IDalBalloon, IDalLiquid
{
//Members
//some form of instantiation
Balloon balloon = new Balloon();
//cast to IDalBalloon to check if it is an IDalBalloon
IDalBalloon isBalloon = balloon as IDalBalloon;

Liquid liquid = new Liquid();
//cast to IDalLiquid to check if it is an IDalLiquid
IDalLiquid isLiquid = liquid as IDalLiquid;

Public void Float()
{
if (isBalloon != null)
isBalloon.Float();
else
throw new Exception("Must implement IDalBalloon");
}

Public void Flow()
{
if (iLiquid != null)
isLiquid.Flow();
else
throw new Exception("Must implement IDalLiquid");
}
}


4) Then in a client.
DalProxy p = new DalProxy;
//invoke Flow()
p.Flow();
//invoke Float()
p.Float();


This solves the first of my two problems: that of having a logical layer of
classes which do all the concrete implementation having to be
interchangeable. In other words I can now have a library of SQL classes:
(SqlBalloon implementing IDalBalloon) and an alternative library of Oracle
classes (OracleBalloon implementing IDalBalloon).

However, using one single Proxy class (DalProxy) for invoking the methods is
not solving the problem of having one DalMain, that I faced in my solution.
It means that the development bottleneck of having the team lining up to
edit DalProxy would still be there!
But the good thing is, I can have a number of specialist Proxy classes,
DalBalloonProxy and DalLiquidProxy which each implements the IDalBalloon and
IDalLiquid interfaces respectively, and each is responsible to their methods
specifically.

Thanks again.
 
J

Jon Skeet [C# MVP]

Codex Twin said:
Thanks! I really like the sound of the second idea you've explained.

From my reading of your solution and the Proxy design pattern (which I
looked up), this is my understanding of your suggestion:

3) Have one proxy which implements all the interface and creates an instance
of the individual classes:

public class DalProxy : IDalBalloon, IDalLiquid

{
//Members
//some form of instantiation
Balloon balloon = new Balloon();
//cast to IDalBalloon to check if it is an IDalBalloon
IDalBalloon isBalloon = balloon as IDalBalloon;

There's no need to do this - just instantiate it as:

IDalBalloon balloon = new Balloon();

The compiler can verify (at compile time) that Balloon implements
IDalBalloon.

However, using one single Proxy class (DalProxy) for invoking the methods
would present the same problem of having one DalMain, that I faced in my
solution. It means that the development bottleneck of having the team lining
up to edit DalProxy would still be there!

They shouldn't - changes to DalProxy should only occur when the
interface changes, as it has no real implementation itself. In
addition, when the interface changes DalProxy only needs to be changed
for a matter of minutes, as the implementation of each method is so
simple.
But the good thing is, I can have a number of specialist Proxy classes,
DalBalloonProxy and DalLiquidProxy which each implements the IDalBalloon and
IDalLiquid interfaces respectively, and each is responsible to their methods
specifically.

I don't think that particularly helps - if you're going to have
separate proxy classes, the caller would have to know which of those to
instantiate, at which point the benefit of having a proxy is almost
entirely gone.
 
C

Codex Twin

They shouldn't - changes to DalProxy should only occur when the
interface changes, as it has no real implementation itself. In
addition, when the interface changes DalProxy only needs to be changed
for a matter of minutes, as the implementation of each method is so
simple.

Yes, sorry, you're right. The only thing that the DalProxy should have is an
implementation of IDalBalloon and IDalLiquid methods which would be
boilerplate code and wouldn't need time consuming check-outs which would
cause the team-time bottlenecks I want to avoid.
I don't think that particularly helps - if you're going to have
separate proxy classes, the caller would have to know which of those to
instantiate, at which point the benefit of having a proxy is almost
entirely gone.

What I tried to get across in my post, but failed completely, was the
question of how I would create a way of switching between libraries. If you
remember in my solution, I had a DataAccessBaseClass, which has a static
method called GetDalLayer() which checks that the type of DalMain "is a"
DalBase, and if it
is, returns the an instace of DalMain. The checking is done by GetDalLayer()
which reads a config file which simply contains the string "DalMain", and if
it inherits from DalBase (which it should), creates an instance of it using
Activator and returns the instance.

Now, if I wanted to use an Oracle implementation, I would have to create a
DalMainForOracle class which would extend DalBase with overridden wrapper
methods specific for Oracle invocations. And then I'd edit the config file
so that DataAccessBaseClass.GetDalLayer() would return an instance of
DalMainForOracle.

Then the code to call Dal methods for either case would always be:

DalBase dal = DataAccessBaseClass.GetDalLayer();
//dal is an instance of DalMain or DalMainForOracle, depending on whats
specified in the config.
dal.Flow();

Using the Proxy method you've suggested, how would I be able to specify, if
possible, whether IDalBalloon is code SQL or Oracle implementation, so to
speak?

Thanks.
 
J

Jon Skeet [C# MVP]

Codex Twin said:
Yes, sorry, you're right. The only thing that the DalProxy should have is an
implementation of IDalBalloon and IDalLiquid methods which would be
boilerplate code and wouldn't need time consuming check-outs which would
cause the team-time bottlenecks I want to avoid.
Exactly.


What I tried to get across in my post, but failed completely, was the
question of how I would create a way of switching between libraries. If you
remember in my solution, I had a DataAccessBaseClass, which has a static
method called GetDalLayer() which checks that the type of DalMain "is a"
DalBase, and if it
is, returns the an instace of DalMain. The checking is done by GetDalLayer()
which reads a config file which simply contains the string "DalMain", and if
it inherits from DalBase (which it should), creates an instance of it using
Activator and returns the instance.

Right. You might want to consider using the Spring framework for this
kind of thing. I'm using it in Java at the moment, and it's wonderful.
I haven't used the .NET version, but I've looked at some of the docs
and it looks basically the same (as I'd expect). See
http://www.springframework.org for more information.

<snip - I think the above covers it>
 
C

Codex Twin

Jon Skeet said:
Right. You might want to consider using the Spring framework for this
kind of thing. I'm using it in Java at the moment, and it's wonderful.
I haven't used the .NET version, but I've looked at some of the docs
and it looks basically the same (as I'd expect). See
http://www.springframework.org for more information.

<snip - I think the above covers it>

I THINK have found a solution which is a happy medium which solves the
problems:
1) Allows a plug-able library by specifying the Library class from a config
file
2) Separates the classes into seprate files which avoid the development
bottleneck.

It uses interfaces rather than base classes and uses the Factory pattern.

The smaller concrete classes must all implement interfaces:
public interface IDalBalloon
{
void Float();
}

By doing so, I can have many files for each class in my DAL - which solves
the second problem, ie a seperate file for Balloon and Liquid
public class Balloon : IDalBalloon
{
public void Float()
{...}
}

public class Liquid: IDalLiquid
{
public void Flow()
{...}
}

I then have a base interface, (if we can call it that) simply defines
methods which return instances of objects of type IDalBalloon

public interface IDataFactory
{
IDalBalloon GetBalloon();
IDalLiquid GetLiquid();
}

This interface is implenmented by the specific implementation of
IDataFactory - these are the Sql and Oracle class libraries which are the
domain specific impementation of either for the Balloon class. An example
would look like this:

public class SqlDataFactory : IDataFactory
{
public IDalBalloon GetBalloon()
{
return new Balloon();
}

public IDalLiquid GetLiquid()
{
return new Liquid();
}
}

Now it is the type SqlDataFactory that I can plug in via the config file. I
could just as specify OracleDataFactory if I need to have an Oracle
implementation.

And then I use this code to return the instance of SqlDataFactory (Factory)

public class DalHelper
{
public static IDataFactory GetDalLayer()
{

string typeName = get the string "SqlDataFactory" from the config

Type type = Type.GetType(typeName);
return (SqlDataFactory)Avtivator.GetInstance(type, true);
}
}

So, from here I can call any implementation of Balloon with these 3 lines of
code:

IDataFactory df = DalHelper.GetDalLayer();
IDalBalloon balloon = df.GetBalloon();
balloon.Float();

I can think its fair to say there are two Factories going on in here. One by
the above code, which returns the SqlDataFactory object. And then the
sub-factory methods in SqlDataFactory itself. But then, I may be wrong! But
it seems to solve my two problems.

I'm off to reclaim my life!
 
J

Jon Skeet [C# MVP]

Codex Twin said:
I THINK have found a solution which is a happy medium which solves the
problems:
<snip>

Goodo.

And then I use this code to return the instance of SqlDataFactory (Factory)

public class DalHelper
{
public static IDataFactory GetDalLayer()
{

string typeName = get the string "SqlDataFactory" from the config

Type type = Type.GetType(typeName);
return (SqlDataFactory)Avtivator.GetInstance(type, true);
}
}

I assume this is meant to be a cast to IDataFactory rather than
SqlDataFactory :)
So, from here I can call any implementation of Balloon with these 3 lines of
code:

IDataFactory df = DalHelper.GetDalLayer();
IDalBalloon balloon = df.GetBalloon();
balloon.Float();

I can think its fair to say there are two Factories going on in here. One by
the above code, which returns the SqlDataFactory object. And then the
sub-factory methods in SqlDataFactory itself. But then, I may be wrong! But
it seems to solve my two problems.

I think you may find it easier to just have one factory in the end,
which can handle everything. (Again, I'd suggest Spring as an excellent
way of doing this - you can use Spring and still have all the same
interfaces etc.) Then again, depending on your needs it may be better
to split it up as you have done...
 

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

Top