Solved

C# OOD Abstraction Principles

Posted on 2009-04-14
18
631 Views
Last Modified: 2012-05-06
Hi there guys,
This will surely sound a bit elementary to the experienced programmer, but I feel I have missed an important concept of Inheritance (particularly abstraction).

The question is simple really:

I have a base class: "Request"
It contains several properties and methods which can be overridden.

Then I have a few derived classes, for example: "LookupRequest"
This classes inherits from Request, and overrides a couple properties/methods as stated above.

However, when creating an instance of LookupRequest using Polymorphism, I've ran into a problem. By typing something like:

Request request = new LookupRequest();

It works, however, I don't have access to any of the LookupRequest properties/methods. Just the base class (Request).

If I create an instance by implicitly typing:
var request = new LookupRequest();

Then I get access to the derived properties / methods as desired.
This seems like I'm missing an important concept to abstraction or polymorphism. Since you abstract classes are not meant and cannot by created instances, how does one properly invoke an inherited class?

Much thanks in advance!

-Danny
0
Comment
Question by:MyAsylum
18 Comments
 

Author Comment

by:MyAsylum
ID: 24144923
Hmm...
After doing a little digging, it seems the proper way to instantiate a derived class is to use the format:

DerivedClass class = new DerivedClass();

I guess I had gotten a bit confused while reading Head First - Design Patterns. In the book they illustrate a sample of polymorphism like so:

Duck mallard = new MallardDuck();
mallard.performQuack();

This code and the book's code is in Java though. So myself, (not being a java guru), I'm assuming Java's syntax uses polymorphism a little differently.
0
 

Author Comment

by:MyAsylum
ID: 24144960
So now I'm curious how would one use C#'s method of polymorphism in a situation like this.
I have a design pattern Factory class which returns an instance of a created class ... see code snippet:

So this doesn't work because it returns an instance of the base class for some weird! reason.
Not only that, but I can't convert awsRequest to an implicit variable or else I'd have to initialize it right away, and I don't yet know which derived class to use.

internal AwsRequest GetOperation(Aws.AwsRequestOperation operation)

{

            AwsRequest awsRequest = null;
 

            switch(operation)

            {

                case Aws.AwsRequestOperation.BrowseNodeLookup:

                    awsRequest = new AwsBrowseNodeLookup();

                    break;

                case Aws.AwsRequestOperation.CartAdd:

                    awsRequest = new AwsCartAdd();

                    break;

                case Aws.AwsRequestOperation.CartClear:

                    awsRequest = new AwsCartClear();

                    break;

           }
 

           return awsRequest;

}

Open in new window

0
 
LVL 29

Accepted Solution

by:
Gautham Janardhan earned 125 total points
ID: 24144962
i would suggest the best way of creating an object would be
Request request = new LookupRequest();
since Request is the base calss. i dont know why it's so..but it's considered as a good practice. so if u want to access the LookupRequest methods then u have to cast it
(request  as LookupRequest).LookupRequestMethod();
0
 

Author Comment

by:MyAsylum
ID: 24145033
That wouldn't work as I'm returning a generic AwsRequest class. Therefore I don't know what derived class I should cast too.
0
 

Author Comment

by:MyAsylum
ID: 24145044
I've found some information on other .net design principles and techniques called early and late binding.
Late binding maybe what I'm looking for, however, I believe it makes use of Reflection.

I originally thought of using something like that, but doesn't all Reflection cause unwanted overhead on the program.
0
 
LVL 29

Expert Comment

by:Gautham Janardhan
ID: 24145093
no if the type is a know type there is no need of reflection .. it's memory hungry and u dont want to go there if it can be avoided. but the concept of a factory calss fits mre into a situation where the child classes only overide functions that are there in the parent and dont need any of their own (they may need more for the internal processing but only the parent functionality is exposed ) and each wud do a job in a way of their own.
for example take an abstract class Animal with abstract methods move, breathe and blah blah blah each animal when implemted from this main class Animal would implement this in its own way.
0
 

Author Comment

by:MyAsylum
ID: 24145125
That's interesting. My child classes override the abstract methods / properties, however they also have new properties which I need access to.

Is this not proper use of abstraction?
Should inherited classes only contain prop/methods from the base class?
0
 
LVL 29

Expert Comment

by:Gautham Janardhan
ID: 24145135
that wud depend on ur requirement. but if u have extra functions and properties in ur child class then using the factory pattern would cause problems as u found out
0
 

Author Comment

by:MyAsylum
ID: 24145171
For certain,
It looks like this is a known issue though. I'm not 100% sure this is what I need yet, but I'm reading it over.

Creating Dynamic Factories in .NET Using Reflection
http://msdn.microsoft.com/en-us/magazine/cc164170.aspx
0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 

Author Comment

by:MyAsylum
ID: 24145179
I would much rather not use Reflection though. This class library will be used in a web environment so I'd like as much efficiency as possible. I'm going to try and re-think my approach.

Thanks for your help gauthampj.
0
 

Author Comment

by:MyAsylum
ID: 24145332
Just want to update for future developers who may stumble upon this topic: this article illustrates a solution for creating dynamic polymorphism via Factory pattern.

Creating Dynamic Factories in .NET Using Reflection
http://msdn.microsoft.com/en-us/magazine/cc164170.aspx

I'm still unsure if I'm going to use this as Reflection is much undesired.
0
 
LVL 74

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 100 total points
ID: 24146081
Unless I'm missing something (and who knows... I haven't slept since yesterday!), your code should be fine. You have to cast the return from the function in order to access the methods of the derived class:
// Somewhere else in code
 

AwsRequest req = null;
 

req = GetOperation(someVariable);

((AwsCartAdd)req).SomeAwsCartAddMethod();
 
 

// Func def
 

internal AwsRequest GetOperation(Aws.AwsRequestOperation operation)

{

            AwsRequest awsRequest = null;

 

            switch(operation)

            {

                case Aws.AwsRequestOperation.BrowseNodeLookup:

                    awsRequest = new AwsBrowseNodeLookup();

                    break;

                case Aws.AwsRequestOperation.CartAdd:

                    awsRequest = new AwsCartAdd();

                    break;

                case Aws.AwsRequestOperation.CartClear:

                    awsRequest = new AwsCartClear();

                    break;

           }

 

           return awsRequest;

}

Open in new window

0
 

Author Comment

by:MyAsylum
ID: 24146839
Hi Kaufmed,
Let me provide a little more code so you can see the whole picture. You're solution would work, however, the method which calls the factory method does not know which derived class it will be returning; therefore a cast would not be possible.

See attached code:

The AwsRequest class contains properties and methods that are common to all it's derived classes. However, each derived class has unique properties and methods which need to be accessible like you illustrated in your last post.

Unfortunately, the only way I could apply a cast would be to use another switch or if statement within the method calling the factory. It would look like:

public AwsRequest CreateRequest(AwsRequestOperation operation)
{
            var awsFactory = new AwsFactory();
            if(operation == AwsRequestOperation.BrowseNodeLookup)
                 return (AwsBrowseNodeLookup)awsFactory.GetOperation(operation);
            else if.....
}
public AwsRequest CreateRequest(AwsRequestOperation operation)

{

            var awsFactory = new AwsFactory();

            return awsFactory.GetOperation(operation);

}
 

-----------------------------------------------------------------------
 

internal sealed class AwsFactory

{

        internal AwsRequest GetOperation(Aws.AwsRequestOperation operation)

        {

            switch(operation)

            {

                case Aws.AwsRequestOperation.BrowseNodeLookup:

                    return new AwsBrowseNodeLookup();

                case Aws.AwsRequestOperation.CartAdd:

                    return new AwsCartAdd();

                case Aws.AwsRequestOperation.CartClear:

                    return new AwsCartClear();

            }

        }

}

Open in new window

0
 

Author Comment

by:MyAsylum
ID: 24146878
I'm surprised that there's not much information on a dynamic factory pattern. Since that is one of the most common. Unless inherited classes are really only meant to contain overridden prop/methods, this leaves a major gap in what the factory can do.

I'm really trying to avoid Reflection.
If anyone would like, I can provide the entire project for download. It's very small as I just started a day or so ago. It's a .NET 3.5 library for Amazons Web Services. It will be released open source for developers to contribute and expand it's functionality.
0
 

Author Comment

by:MyAsylum
ID: 24146921
I'm going about this the wrong way.
Even if it could return the correct derivedType, the programmer wouldn't be able to use the derived class's unique methods or properties since that would only be known at runtime.
0
 
LVL 8

Assisted Solution

by:ppittle
ppittle earned 25 total points
ID: 24148345
MyAsulum,

My two cents on the matter:

Inhertience / Polymorphism is a solution for many common software development / architecture problmes.  The applications of Inheritence and Ploymorphism are vast but can be practically sumarized scenarios:

1)  You are creating several classes that all have common Properties and/or Methods in common.  OO heavily encourages code-reuse, as it reduces needed testing, increases maintability, etc.  In this case, you can create a common base class that contains all of the common Properties and Methods.  However, in this situation, the child classes are generally specialized and meant to be used directly.  Any code that makes use of your child classes should create the directly (ie ChildClass cc = new ChildClass()).  In this scenario, having a base class is purely a convienance for the developer building the ChildClasses.  This sounds like what you're going for.

2) The second scenario is when the base class defines all of the methods neccessary to work with a child object.  The base class might not implement all of these methods, but they are defined.  It would then be the child classes' resposability to implement the methods that do actual work.  This is where the power of Polymorphism really comes into play.  A great example for this is the Stream class.  You can not instantiate a Stream class directly, it's an abstract class.  However, the Stream class defines all of the methods neccessary to work with a Stream (ie Read, Write, Seek, etc).  So now it's up to the child classes (FileStream, MemoryStream, NetworkStream) to provide the actual implementation, define what happens when Read, Write, Seek, etc are called.  The cool thing, is you can now write classes such as StreamReader, StreamWritter, that can provide buffered reading and writing on ANY Stream class.  In other words, you can create another set of utility classes that are designed to work against the baseclass.

To tie this back to your Request example, if the Request base class does not contain defintions (note: it does not need to implement the method, just provide the definition, ie public abstract void DoWork();) for enough methods / properties that it a caller can work witha  Request class, then you need to re-think your architecture, or force a consumer of your code to work directly with the child classes.
0
 

Author Comment

by:MyAsylum
ID: 24155991
Sorry about the delayed response. I've modified the architecture a bit so this is no longer a problem. I really just wasn't thinking too clearly before and it doesn't help what you jump into programming before any significant planning or diagramming.

Thanks ppittle for your response. I'm using abstraction because the base class contains several overridden properties/methods for the child classes.

I've bumped up the points and will divide them out. :) Thanks again for all your input.
0
 
LVL 29

Expert Comment

by:Gautham Janardhan
ID: 24158359
can u say how u modified ur soln ? just curious :-)
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now