views:

184

answers:

6

I'm trying to get the wheels turning on a large project in C#. My previous experience is in Delphi, where by default every form was created at applicaton startup and form references where held in (gasp) global variables. So I'm trying to adapt my thinking to a 100% object oriented environment, and my head is spinning just a little.

My app will have a large collection of classes Most of these classes will only really need one instance. So I was thinking: static classes. I'm not really sure why, but much of what I've read here says that if my class is going to hold a state, which I take to mean any property values at all, I should use a singleton structure instead. Okay. But there are people out there who for reasons that escape me, think that singletons are evil too.

None of these classes is in danger of being used anywhere except in this program. So they could certainly work fine as regular objects (vs singletons or static classes)

Then there's the issue of interaction between objects. I'm tempted to create a Global class full of public static properties referencing the single instances of many of these classes. I've also considered just making them properties (static or instance, not sure which) of the MainForm. Then I'd have each of my classes be aware of the MainForm as Owner. Then the various objects could refer to each other as Owner.Object1, Owner.Object2, etc.

I fear I'm running out of electronic ink, or at least taxing the patience of anyone kind enough to have stuck with me this long. I hope I have clearly explained my state of utter confusion. I'm just looking for some advice on best practices in my situation. All input is welcome and appreciated.

Thanks in advance, David Jennings

+5  A: 

It's very normal to go from procedural or other non-OOP languages and think "One giant static class per XYZ", and that normally means you've not really thought about the OBJECTS that are being represented because a class should represent the OBJECTS that are to be manipulated.

So, you need to step back and look at the DATA and what the DATA represents. You might say, "Well, it's DATA! It represents NUMBERS!", but you have to abstract out what the data represents. The "thing" that the data represents is the Object. The actions you perform on the data the "thing" represents then becomes your methods.

Julie in Austin
This project is actually a rewrite of a system I developed in Delphi about 8 years ago. I've been maintaining and improving the application ever since, and I've just decided it's time to leave Delphi behind. Delphi is an object oriented language (mostly). It's just got that global storage piece mixed in (which most object oriented programmers, no doubt rightly, find cringeworthy). So as far as translation of data/behavior to classes, I think I'm pretty well set. Where I'm floundering a bit, is figuring out the BEST way to leave the global space behind.
David Jenings
+2  A: 

You could try it and see how it goes. Consider developing with NUnit at your side; if you do you'll find that your code will stay flexible enough that making architectural changes won't be too tough.

My preference is to avoid static classes and static data, but sometimes it just makes sense for the near term problem. On that, my advice is to consider what actually owns the various forms. Oftentimes it seems that people want to make the main form the "primary application thing," but maybe there actually is a better owner for that form.

Anyway- beyond talking about and musing on what could be, I'd suggest just going ahead and trying some options out and see what they do. Don't be afraid to change your software after you write it!

dash-tom-bang
Thanks for that. It's kind of the attitude I'm beginning with. I feel confident I can make the application work no matter how I approach these particular issues. I'd just like to learn something in the process, and also keep the application from becoming a hairy mess right out of the gate. :)
David Jenings
+1  A: 

Singletons are usually the source of many problems that we usually see in a design. However I consider creating both singletons and globals as a means to pass them around the app as a code smell.

I feel it would do good to get yourself a primer on SOLID Principles. There are also several dimecasts on this topic that you should watch and understand.

Another practical book that I would recommend is Implementation Patterns by Kent Beck. Understanding OOP is one thing and implementing in the real world is a different thing.

Take a look at Windows Presentation Foundation, a next-generation presentation system for building Windows client applications.

I think I bombarded you with enough information, but take it easy and go one step at a time. I feel you should follow couple of tracks here to get to where you want to be. There are some prototypes that microsoft offers that you can learn from and then improvise with OOP.

CodeToGlory
A: 

Just a few random thoughts on this which may or may not be useful:

  • Start with the data not the program structure. Analyse the data and figure out what you are conceptually trying to represent and then objectify it.

  • My experience is that with prodedural code you are thinking "What am I doing now?" but with OO code you are thinking "What might I want to do someday?"

  • There will always be at least one master object, even if that is the Application object itself. Don't put too much in this object even though it is tempting. The more you represent data, state and behaviour in conceptually relevant objects the easier the app will be to learn and maintain for new developers.

  • Do a prototype. Build a scaled down version of your app that you know you will discard and then when you get to a certain point review your code, decide which objects worked well and which didn't and start again.

As for the whole Singleton thing - and without wanting to be provocative - ignore the naysaysers. There are times when the Singleton design pattern is fantastically useful just as there are times when an EAV data model is perfect and MVC is the worst thing in the world. If you need to put in a screw, use a screwdriver.

James
A: 

In reading your explanation part of me thinks that you might be still be thinking in a Delphi kind of paradigm if you have that many classes you think should be static or singletons. I don't know if I've ever encountered a project where there was just one of most objects. So my inclination is that your object decomposition might be flawed.

Really you should really start thinking about what you are representing in your program. Ask yourself, if you have a lot of objects that only have one instance why is there only one instance? Is it because you are holding data in an odd way like having multiple arrays whose indexes matches.

That being said C# does have some good built in semantics for singletons in that you don't have to do the null checking in your instance method

public class SingletonClass{
     private static SingletonClass _instance;

     private SingletonClass(){}

     public static Instance
     {
         get
         {
             if(_instance == null){
                _instance = new SingletonClass();
             }
         }
     }

}

In C# can be written as:

public class SingletonClass{ private static SingletonClass _instance = new SingletonClass();

     private SingletonClass(){}

     public static Instance
     {
         get
         {
            return _instance;
         }
     }

}

So I would recommend leaning towards using Singletons if you insist on using the pattern. Singletons, like everything have a time and place, I wouldn't write a whole app where the majority objects are singletons.

I'd highly encourage you to think of why you have a global state with static methods or singletons.

Craig Suchanec
A: 

Static classes and Singletons share the same drawbacks:

  • Tightly coupled to many other classes
  • Hide dependencies (hard to tell what other classes use them)
  • Testing difficulties
  • Essentially global data
  • For Singletons, multiple responsibilities (whatever they do + lifetime management)

The solution in many (not all!) cases is Dependency Injection (DI), based on the Dependency Inversion Principle (one of the SOLID principles that @CodeToGlory mentioned). This can be done manually or with a DI Container framework.

Mark Seemann has a book coming out on Dependency Injection in .NET; you might want to check out the early access edition. (I haven't read it yet, but Seemann's written some excellent posts on the subject.)

TrueWill