Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

What is the best practice when it comes to writing classes that might have to know about the user interface. Wouldn't a class knowing how to draw itself break some best practices since it depends on what the user interface is (console, GUI, etc)?

In many programming books I've come across the "Shape" example that shows inheritance. The base class shape has a draw() method that each shape such as a circle and square override. This allows for polymorphism. But isn't the draw() method very much dependent on what the user interface is? If we write this class for say, Win Forms, then we cannot re-use it for a console app or web app. Is this correct?

The reason for the question is that I find myself always getting stuck and hung up on how to generalize classes so they are most useful. This is actually working against me and I'm wondering if I'm "trying too hard".

share|improve this question
    
Why do you want to decouple? Because you heard it was the right thing to do or do you have other reasons? –  Chad Jul 26 '11 at 19:59
1  
The whole "class knowing how to draw itself" is just a horrible, ancient example I wish would disappear. Especially on the game programmer's stack =) –  Patrick Hughes Jul 26 '11 at 20:10
2  
@Chad I am not really experienced much outside of school. I've read books and I genuinely like learning and reading new things about design patterns and best practices. So yes, you can say I've heard that decoupling is good but it also makes sense. I want to write code that I can use for a desktop WinForms app, for example, then take that code and reuse as much as possible for a website or even a silverlight app. –  Pete Jul 27 '11 at 1:56
    
@Pete - That is a good answer. –  Chad Jul 27 '11 at 13:23
2  
@Patrick: to be fair, if you're writing a Shape class, then you're probably writing the graphics stack itself, not writing a client to the graphics stack. –  Ken Bloom Jul 27 '11 at 14:09

8 Answers 8

up vote 10 down vote accepted
+50

What is the best practice when it comes to writing classes that might have to know about the user interface. Wouldn't a class knowing how to draw itself break some best practices since it depends on what the user interface is (console, GUI, etc)?

That depends on the class and the use case. A visual element knowing how to draw itself is not necessarily a violation of the single responsibility principle.

In many programming books I've come across the "Shape" example that shows inheritance. The base class shape has a draw() method that each shape such as a circle and square override. This allows for polymorphism. But isn't the draw() method very much dependent on what the user interface is?

Again, not necessarily. If you can create an interface (drawPoint, drawLine, set Color etc.), you can pretty much pass any context for drawing things onto something to the shape, for example within the shape's constructor. This would enable shapes to draw themselves on a console or any canvas given.

If we write this class for say, Win Forms, then we cannot re-use it for a console app or web app. Is this correct?

Well, that's true. If you write a UserControl (not a class in general) for Windows Forms, then you won't be able to use it with a console. But that's not a problem. Why would you expect a UserControl for Windows Forms to work with any kind of presentation? The UserControl should do one thing and do it well. It's bound to a certain form of presentation by definition. In the end, the user needs something concrete and not an abstraction. This might only be partly true for frameworks, but for end-user applications, it is.

However, the logic behind it should be decoupled, so you can use it again with other presentation technologies. Introduce interfaces where necessary, to maintain orthogonality for your application. The general rule is: The concrete things should be exchangeable with other concrete things.

The reason for the question is that I find myself always getting stuck and hung up on how to generalize classes so they are most useful. This is actually working against me and I'm wondering if I'm "trying too hard".

You know, extreme programmers are fond of their YAGNI attitude. Don't try to write everything generically and don't try too hard trying to make everything general purpose. This is called overengineering and will eventually lead to totally convoluted code. Give each component exactly one task and make sure it does it well. Put in abstractions where necessary, where you expect things to change (e.g. interface for drawing context, like stated above).

In general, when writing business applications, you should always try to decouple things. MVC and MVVM are great to decouple the logic from the presentation, so you can reuse it for a web presentation or a console application. Keep in mind that in the end, some things have to be concrete. Your users can't work with an abstraction, they need something concrete. Abstractions are only helpers for you, the programmer, to keep the code extensible and maintainable. You need to hink about where you need your code to be flexible. Eventually all abstractions have to give birth to something concrete.

Edit: If you want to read more about architecture and design techniques which can provide best practices, I suggest you read @Catchops answer and read about SOLID practices on wikipedia.

Also, for starters, I always recommend the following book: Head First Design Patterns. It'll help you understand abstraction techniques/OOP design practices, more so than the GoF book (which is excellent, it just doesn't suit beginners).

share|improve this answer
1  
Good answer, but extreme programmers don't 'put in abstractions where we expect things to change'. We put in abstractions where things are changing, to DRY up the code. –  kevin cline Jul 29 '11 at 4:53
1  
@kevin cline that's awesome unless you are designing a publicly available library with an API that needs to conform to previous behaviour and interfaces. –  Magnus Wolffelt Aug 1 '11 at 14:38
    
@Magnus - yes, designing a library in a some languages, planning for backward binary compatibility, is tricky. One is forced to write all sorts of currently unneeded code to allow for future extension. This may be reasonable for languages that compile to the metal. It's silly for languages that compile to a virtual machine. –  kevin cline Aug 2 '11 at 16:15

You are definitely right. And no, you are "trying just fine" :)

Read about the Single responsibility principle

Your inner working of the class and the way this information should be presented to the user are two responsibilities.

Don't be afraid to decouple classes. Rarely the problem is too much abstraction and decoupling :)

Two very relevant patterns are Model–view–controller for web applications and Model View ViewModel for Silverlight / WPF.

share|improve this answer
1  
+1 You can even use MVC for not-web applications, at the very least it helps you think in terms that keep the responsibilities clear. –  Patrick Hughes Jul 26 '11 at 20:13
    
MVVM is silimar to MVC. MVC is mostly for stateless applications like web apps. –  Boris Yankov Jul 27 '11 at 15:04
3  
-1 In my experience one of the most common problems is premature generalization and over-engineering in general. –  dietbuddha Jul 29 '11 at 21:26
2  
You first need to know how to engineer something in order to over-engineer it. In my experience, people 'under-engineer' software much more often. –  Boris Yankov Jul 29 '11 at 21:45
    
While I appreciate efforts to improve software design, substituting a call on an interface, for a call on a class, does not decouple anything semantically. Consider what happens when using a dynamically typed language. There is far too much emphasis on superficial (syntactic) decoupling, and little on true decoupling, in the advice provided in the programmers section of stack exchange. –  Frank Hileman Aug 22 at 18:26

I use MVVM a lot and in my opinion, a business object class should never need to know anything about the user interface. Sure they might need to know the SelectedItem, or IsChecked, or IsVisible, etc but those values do not need to tie into any particular UI and can be generic properties on the class.

If you need to do something to the interface in code behind, such as setting Focus, running an Animation, handling Hot Keys, etc then the code should be part of the UI's code-behind, not your business logic classes.

So I would say don't stop trying to split apart your UI and your classes. The more decoupled they are, the easier they are to maintain and test.

share|improve this answer

There are a number of tried and true design patterns that have been developed over the years to address exactly what you are talking about. Other answers to your question have referred to the Single Reponsibility Principle - which is absolutely valid - and what seems to be driving your question. That principle simply states that a class needs to do one thing WELL. In other words raising Cohesion and lowering Coupling which is what good object oriented design is all about - does a class do one thing well, and not have a lot of dependencies on others.

Well...you are right in observing that if you want to draw a circle on an iPhone, it will be different than drawing one on a PC running windows. You MUST have (in this case) a concrete class that draws one well on the iPhone, and another that draws one well on a PC. This is where the basic OO tenent of inheritance that all of those shapes examples breaks down. You simply cannot do it with inheritance alone.

That is where interfaces come in - as the Gang of Four book states (MUST READ) - Always favor implementation over inheritance. In other words, use interfaces to piece together an architecture that can perform various functions in many ways without relying on hard coded dependencies.

I've seen referece to the SOLID principles. Those are great. The 'S' is the single responsiblity principle. BUT, the 'D' stands for Dependency Inversion. The Inversion of Control pattern (Dependency Injection) can be used here. It is very powerful and can be used to answer the question of how to architect a system that can draw a circle for an iPhone as well as one for the PC.

It is possible to create an architecture that contains common business rules and data access, but have various implementations of user interfaces using these constructs. It really helps, however, to have actually been on a team that implemented it and see it in action to really understand it.

This is just a quick high-level answer to a question that deserves a more detailed answer. I encourage you to look further into these patterns. Some more concrete implementation of these patters can be found as well known names of MVC and MVVM.

Good luck!

share|improve this answer
    
I love it when someone downvotes something without giving a comment as to why (sarcasm, of course). The principles I stated are true - would the downvoter please stand up and say why. –  Catchops Aug 1 '11 at 12:41

There are different patterns to do that: MVP, MVC, MVVM, etc...

A nice article from Martin Fowler (big name) to read is GUI Architectures: http://www.martinfowler.com/eaaDev/uiArchs.html

MVP has not been mentioned yet but it definitely deserve to be cited: take a look at it.

It's the pattern suggested by the developers of Google Web Toolkit to use, it's really neat.

You can find real code, real examples and rationale on why this approach is useful here:

http://code.google.com/webtoolkit/articles/mvp-architecture.html

http://code.google.com/webtoolkit/articles/mvp-architecture-2.html

One of the advantages of following this or similar approaches which has not been stressed enough here is the testability! In a lot of cases I would say that is the main advantage!

share|improve this answer
1  
+1 for the links. I was reading a similar article on MSDN about MVVM and those google articles are much better though on a slightly different pattern. –  Pete Jul 28 '11 at 6:21

What is the best practice when it comes to writing classes that might have to know about the user interface.

Wouldn't a class knowing how to draw itself break some best practices since it depends on what the user interface is (console, GUI, etc)?

In this case you can still use MVC/MVVM and inject different UI implementations using common interface:

public interface IAgnosticChartDrawing
{
   public void Draw(ChartProperties chartProperties);
   event EventHandler ChartPanned;
}

public class GuiChartDrawer : UserControl, IAgnosticChartDrawing
{
    public void Draw(ChartProperties chartProperties)
    {
        //GDI, GTK or something else...
    }

    //Implement event based on mouse actions
}

public class ConsoleChartDrawer : IAgnosticChartDrawing
{
    public void Draw(ChartProperties chartProperties)
    {
        //'Draw' using characters and symbols...
    }

    //Implement event based on keyboard actions
}

IAgnosticChartDrawing guiView = new GuiChartDrawer();
IAgnosticChartDrawing conView = new ConsoleChartDrawer();

Model model = new FinancialModel();

SampleController controllerGUI = new SampleController(model, guiView);
SampleController controllerConsole = new SampleController(model, conView);

This way you will be able to re-use your Controller and Model logic while being able to add new types of GUI.

share|improve this answer

This is one of the places where OOP fails to do a good job at abstraction. OOP polymorphism uses dynamic dispatch over a single variable ('this'). If the polymorphism was rooted at Shape then you cannot polymorphic-ally dispatch on the renderer (console, GUI etc).

Consider a programming system which could dispatch on two or more variables:

poly_draw(Shape s, Renderer r)

and also suppose the system could give you a way to express poly_draw for various combinations of Shape types and Renderer types. It would then be easy to come up with a classification of shapes and renderers right? The type checker would somehow help you figure out is there were shape and renderer combinations which you may have missed implementing.

Most OOP languages don't support anything like above (a few do, but they are not mainstream). I would suggest you take a look at the Visitor pattern for a workaround.

share|improve this answer

...isn't the draw() method very much dependent on what the user interface is? If we write this class for say, Win Forms, then we cannot re-use it for a console app or web app. Is this correct?

Above sounds correct to me. Per my understanding, one can say it means relatively tight coupling between Controller and View in terms of MVC design pattern. This also means that to switch between desktop-console-webapp one will have to accordingly switch both Controller and View as a pair - only model remains unchanged.

...I find myself always getting stuck and hung up on how to generalize classes so they are most useful.

Well my current take on above is that this View-Controller coupling we're talking about is OK and even more, it's rather trendy in modern design.

Though, a year or two ago I also felt insecure about that. I've changed my mind after studying discussions at Sun forum on patterns and OO design.

If you're interested, try this forum yourself - it has migrated to Oracle now (link). If you get there, try pinging guy Saish - back then, his explanations on these tricky matters turned out most helpful to me. I can't tell though if he still participates - myself I haven't been there for quite a while

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.