Design pattern

P

phancey

I am trying to implement design patterns but not yet accomplished at
them.

I have a DataFactory that provides my business layer with objects. I
have a static property (Factory) that returns the specific type of
DataFactory in use (SqlServer in my case - a singleton).

I would like the business layer to be able to ask for a new instance
of a Job like this DataFactory.Factory.GetJob<T> where T is a specific
type of Job (MonitorJob etc) but T will only be indicating the
abstract version of it - there will be an actual SqlMonitorJob that is
the specific version but I do not want my business layer to be
bothered with that.

so the Business layer would ask DataFactory.Factory.GetJob<MonitorJob>
but would actually get a SqlMonitorJob. How should I code this to
avoid switch statements etc?

thanks
Phil
 
P

phancey

I am trying to implement design patterns but not yet accomplished at
them.

I have a DataFactory that provides my business layer with objects. I
have a static property (Factory) that returns the specific type of
DataFactory in use (SqlServer in my case - a singleton).

I would like the business layer to be able to ask for a new instance
of a Job like this DataFactory.Factory.GetJob<T> where T is a specific
type of Job (MonitorJob etc) but T will only be indicating the
abstract version of it - there will be an actual SqlMonitorJob that is
the specific version but I do not want my business layer to be
bothered with that.

so the Business layer would ask DataFactory.Factory.GetJob<MonitorJob>
but would actually get a SqlMonitorJob. How should I code this to
avoid switch statements etc?

thanks
Phil

if my Factory had methods like GetMonitorJob then obviously I could
just call that and my factory would then return a SqlMonitorJob but I
would prefer to use a Generic method passing in the type......
 
T

TDC

Assuming you've got an Abstract DataFactory, with a concrete subclass
SqlDataFactory, then the factory methods in SqlDataFactory such as
GetMonitorJob() would return an SQLServer sepecic version of the
Abstract Job object, SqlMonitorJob. The business layer will not see
any "Sql" classes, it would work just with the Abstract classes. That
way you could later have a MySqlDataFactory creating a MySqlMonitorJob
without impacting the business layer.
 
P

phancey

Assuming you've got an Abstract DataFactory, with a concrete subclass
SqlDataFactory, then the factory methods in SqlDataFactory such as
GetMonitorJob() would return an SQLServer sepecic version of the
Abstract Job object, SqlMonitorJob.  The business layer will not see
any "Sql" classes, it would work just with the Abstract classes.  That
way you could later have a MySqlDataFactory creating a MySqlMonitorJob
without impacting the business layer.







- Show quoted text -

yes I have set it up like that.

Abstract DataFactory has static property Factory which returns a
singleton instance of SqlDataFactory.
And yes DataFactory has a GetMonitorJob which returns a SqlMonitorJob
as per my second post. But that means that every time I create a new
type of job (because SqlMonitorJob basically is a Job (that has a
Start method and Status property) but passing in a specific jobName
string in the base constructor like so: public SqlMonitorJob : base
("MonitorImport"){}) I have to create a new method in my factory to
create an instance of this type of job.
i.e. I want a ProcessJob.
create a new ProcessJob inherited from Job.
Then instead of just being able to call GetJob<ProcessJob> from my
business layer and getting my Sql specific one back because that is
the one being provided by my DAL, I have to code a new method
GetProcessJob in my DataFactory.

What I would rather do is to create a new type of job and then be able
to call it generically using GetJob<T> thereby avoiding having to add
in the extra new method to my DataFactory making it more generic.

thanks for your help
 
P

phancey

Well, why can you just use a generic object type of Object and cast it
to what you want after it is returned?- Hide quoted text -

- Show quoted text -

sorry, I don't understand. How would my data layer know I wanted a
ProcessJob? I want to call GetJob<T> specifying an abstract type of
job but getting a concrete one but I don't want the caller to be
bothered about knowing the concrete class. I also do not want to have
a different method for each abstract derivation of Job (ie
GetProcessJob, GetImportJob etc).

public abstract Job
{
public abstract int Start();
public abstract int Status {get;}
}

public abstract ProcessJob : Job
{
}

public class SqlProcessJob : ProcessJob
{
/*implementation*/
}
 
P

phancey

A common way to avoid switch statements in OOP is to take advantage of  
polymorphism.

The usual reason to use a generic type or method is to take advantage of a  
block of code that is identical other than the specific type being used.

If you have a situation where one or the other or both of those apply,  
then you can use one or the other or both to solve your problem.

In your particular case, it is not clear why you feel that a generic  
method is useful.  Why is it that the GetJob<T>() method is exactly the 
same, except for the type parameter being provided?  Based on your  
question, I have the sense that it's not.

The polymorphism applies, in that you can have a DataFactory implemented  
by one of a variety of providers, and then _it_ can do the mapping to the 
appropriate job type.  But I don't see how a generic method comes into  
play.

You _could_ use a dictionary to map from the generic parameter T to the  
derived type you want.  You could even make the dictionary's value typebe  
a delegate function that instantiates the particular type associated with 
the given generic parameter.  But what value are you adding by doing  
that?  In this particular case, what code would be repeated if you wereto  
just make multiple "Get...Job()" methods (e.g. "GetMonitorJob()").

Without knowing more about your specific scenario, it's difficult to  
answer the question in a useful way.  Based on what you've posted so far,  
there's no evidence that a generic method is actually going to be helpful 
to you, and so it's difficult to suggest how you might get a generic  
method to work in a way that makes any sense.

Pete

ok, well it is entirely possible that I am not approaching it in the
rignt manner but this is the scenario.

I have a UI that needs to trigger a database job (or possibly a few).
This is, say, to import some files into the database. Now in SqlServer
this could be implemented as a Sql Server Agent Job where in other
databases it might be different but as far as the UI/Business Layer is
concerned it will want an instance of a Job and then invoke the Start
method. So it calls into the Data Layer and says give me "this type"
of job.

So I could code methods in the data layer for every type of job in the
abstract data factory and then use polymorphism to return a SQL Server
specific instance - which in fact is what I am doing, actually using a
generic IJob interface, but it means that if I want another type of
job (say Export) I have to create a new GetExportJob which is then
overridden in the SqlDataFactory to return a SqlExportJob.

What I would rather do if possible is to just call the
DataFactory.GetJob<ExportJob> method thereby avoiding clogging up my
DataFactory class with lots of generic GetJob methods that all return
some kind of job.

Being fairly new to design patterns I am happy to learn the best way
of doing this.

thanks
 
P

Paul

Right....It seems to me you are confused.

You are merging BLL functionality with Data Access Functionality. Why not
take another approach and split these. below is a basic strategy & factory
method type pattern for a BLL pattern. This is provided as is and is not
correct code but should give the idea and apologies for spelling no time to
correct.

On top af that, ideally seperate out a Data Provider from a DAL. A
DataProvider talks to a DB and returns a IDataReader and all parameters take
IDBParameter etc tec.

You DAL converts Model to DB and DB to Model and uses the System.Data
interface types to do so. To make it simpler to use your DAL you may want to
add a Facade/Set of Handlers on the front for dealing with different model
types.


Here is a BLL pattern


interface IBusinessLogicPattern
{
void executeJob

//Only use the Interface if you want to abstract all BLL tasks under one
roof so to speak.
}


abstract class AbstractJob : IBusinessLogicPattern
{
abstrcat void executeJob;
}

static class JobFactory
{
AbstractJob CreateJob( string/enum/type job)
{
///This can be done in clever ways but why make it dificult
switch (param that refers to creation of Job)
{
case : blah
return new blahJob
case : boo
return new booJob
default
return new allJobs
}
}
}

sealed class blahJob:AbstractJob
{
public void execute()
{
BlahRecords records = DALFacade.FetchBlahRecords();
...do some work...
DALFaceade.Save(records);
}
}

sealed class booJob:AbtsractJob
{
public void execute()
{
BooRecords records = DALFacade.BooRecords();
...do some work...
DALFaceade.Save(records);
}
}


finally implement any composite types

abstract class CompositeJob :AbstractJob
{
Ilist<IBuisinessLogicPattern> jobs;

abstract void executeJob;
}

sealed class allJobs :CompositeJob
{

public allJobs ()
{
//These can be set manualy but can be done here
//Can also be swapped around added more then once, use a queue or
stack rather than list etc etc
//and can be set via config/db
jobs = new ........................
jobs.add(JobFactory.CreateJob(blah));
jobs.add(JobFactory.CreateJob(boo));
}
public void execute()
{
For Each(IBuisinessLogicPattern job in jobs)
{
//lets execute a set of jobs
job.execute();
}
}
}




Hope it helps??
 
P

phancey

Right....It seems to me you are confused.

You are merging BLL functionality with Data Access Functionality. Why not
take another approach and split these. below is a basic strategy & factory
method type pattern for a BLL pattern. This is provided as is and is not
correct code but should give the idea and apologies for spelling no time to
correct.

On top af that, ideally seperate out a Data Provider from a DAL. A
DataProvider talks to a DB and returns a IDataReader and all parameters take
IDBParameter etc tec.

You DAL converts Model to DB and DB to Model and uses the System.Data
interface types to do so. To make it simpler to use your DAL you may wantto
add a Facade/Set of Handlers on the front for dealing with different model
types.

Here is a BLL pattern

interface IBusinessLogicPattern
{
    void executeJob

    //Only use the Interface if you want to abstract all BLL tasks under one
roof so to speak.

}

abstract class AbstractJob : IBusinessLogicPattern
{
    abstrcat void executeJob;

}

static class JobFactory
{
    AbstractJob CreateJob( string/enum/type job)
    {
        ///This can be done in clever ways but why make it dificult
       switch (param that refers to creation of Job)
        {
            case : blah
                return new blahJob
            case : boo
                return new booJob
            default
                return new allJobs
        }
    }

}

sealed class blahJob:AbstractJob
{
       public void execute()
        {
            BlahRecords records = DALFacade.FetchBlahRecords();
            ...do some work...
            DALFaceade.Save(records);
        }

}

sealed class booJob:AbtsractJob
{
       public void execute()
        {
            BooRecords records = DALFacade.BooRecords();
            ...do some work...
            DALFaceade.Save(records);
        }

}

finally implement any composite types

abstract class CompositeJob :AbstractJob
{
    Ilist<IBuisinessLogicPattern> jobs;

   abstract void executeJob;

}

sealed class allJobs :CompositeJob
{

    public allJobs ()
    {
        //These can be set manualy but can be done here
        //Can also be swapped around added more then once, use a queue or
stack rather than list etc etc
        //and can be set via config/db
        jobs = new ........................
        jobs.add(JobFactory.CreateJob(blah));
        jobs.add(JobFactory.CreateJob(boo));
    }
       public void execute()
        {
               For Each(IBuisinessLogicPattern job in jobs)
                {
                    //lets execute a set of jobs
                    job.execute();
                }
        }

}

Hope it helps??

well thanks for your time but I disagree that I am confusing things. I
am in fact pretty much following your pattern. Where it is located is
actually not relevant (to the original post though I will consider it
as a separate issue). The point is you (as I have done) revert to
using a switch statement to decide which job to create. I simply
wanted to know how, if at all, I could code that bit without the
switch statement using CreateJob<T> which would somehow do a new T()
but using the specific version. I couldn't figure out if this pattern
could be implemented. It would be infinitely preferable and more
easily maintainable than having to add another "case" every time I
create a new type of job........

thanks
 
P

Paul

But where it is located is key. Interfaces are important to abstracting
information, trying to make a square peg fit in a round hole ends up with
you bashing it with a hammer. There are obviously many ways to create an
object but at somepoint you need to identify what object you are trying to
create. The code I gave you was a basic factory method held in a factory
class, not necessary but helps keep code tidy, and used infromation passed
to determine the type to instantiate.

Adding 2 lines of code to a switch statement is the least of your problems,
as you are creating a new strategy in any case. Why do people get so
wrappeed up in saving two lines of code.

However if you are so wrapped up in this and want something that requires no
recompiling of code when adding new strategies then create a mechanism
called in the default of the switch to load an assembly at runtime
containing a Type that inherits from your base type, instantiate this and
pass it back.

I don't understand why you are using generics, this sort of says to me you
know what type you are creating in any case which, and if so why not just
instantiate this from the calling code.

You may not be confused it may just be that you have not given enough
information. If you have read 'The Gang of Four' and still cannot comeup
with the answer then maybe just maybe you need to look at what you are doing
and if it is fundamentaly flawed for the tools you have available.
 

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