|
From: Sasa on 4 Sep 2006 13:44 Hi, Sorry for pushing the topic, but I still have some doubts about it and would like to hear from you. The example I'm going to give is based on the .NET Windows Forms, but it's really a design related question not related to technology. I'll try to explain the relevant stuff to non .NET people, so if you have patience/time read on... In .NET world, there is a class called Form which essentially represents a windows form (basically standard MS Windows' window). A Form class has fairly large interface which can be used to manipulate the window. This includes methods/properties such as changing window position/size, setting its style, back color, caption etc. as well as adding child controls. When designing custom form via MS Visual Studio designer, the corresponding C# code (if one does it in C# project of course) is designed which uses the aforementioned class Form and its interface to achieve the look created in the designer. Following are facts about generated code: 1. The generated code is placed in a separate class. 2. The class is derived from the Form class. 3. The generated code uses only public features of the Form class. It introduces no overrides. 4. For each child control added to the form via the designer, the appropriate member variable is added to the generated class. I can use this member to manipulate the child control in the runtime. 5. For each event I want to handle, the designer creates appropriate method in the generated class. In the spirit of the topic I started earlier ("yet another deriving question") I would say that there is no need to derive from the Form. The generated code could easily be modified to instantiate the Form class and achieve the desired look by using its public interface. Now, new class still must be created, if nothing else then because of points no. 4 and 5. But there is no need for this class to be derived from the Form. Benefit of such approach: If the generated class would wrap the instance of the Form as a private member (rather than inheriting from it), it could protect its users from the direct dependency to the Form class. Downsides: 1. It is hard to imagine that .NET Windows Forms developer will ever want to use something else. 2. If the generated class is derived from the Form its users get the usual Form public interface for free. Recall what I said, that the Form class has large interface. This could be resolved by making the generated class contain and return the reference to the contained Form, but by doing this, the single benefit gets lost. This re raised some basic questions. Is polymorphism (as the VS designer uses it) appropriate here, even though the derived class doesn't change the behavior, but only adds new one? Which approach do you see as preferable and why? Thanks, Sasa
From: Frans Bouma on 5 Sep 2006 05:58 Sasa wrote: > In .NET world, there is a class called Form which essentially > represents a windows form (basically standard MS Windows' window). A > Form class has fairly large interface which can be used to manipulate > the window. This includes methods/properties such as changing window > position/size, setting its style, back color, caption etc. as well as > adding child controls. > > When designing custom form via MS Visual Studio designer, the > corresponding C# code (if one does it in C# project of course) is > designed which uses the aforementioned class Form and its interface > to achieve the look created in the designer. > > Following are facts about generated code: > 1. The generated code is placed in a separate class. > 2. The class is derived from the Form class. > 3. The generated code uses only public features of the Form class. It > introduces no overrides. Why would it use overrides? The thing is: the code which makes up YOUR form is stored in a method, called InitializeComponent. That method is called from the constructor generated into the code which makes up your form. This is done on purpose. Say, this wasn't done and InitializeComponent was a method of the class Form, called from its empty constructor (i.e. no parameters). There's no constructor generated into your form code, just an override of the InitializeComponent method. Now, you create a new constructor which accepts a parameter. Your form doesn't work anymore, as the base constructor isn't called. With the method generated into the empty constructor, you see you need to call that method in the constructor. It's still not solid though, but there's no real solution for this, other than introducing a pre-load method which is called by the framework. This actually creates more confusion: what happens when?, the same confusion seen with ASP.NET forms. > 4. For each child control added to the form > via the designer, the appropriate member variable is added to the > generated class. I can use this member to manipulate the child > control in the runtime. > 5. For each event I want to handle, the > designer creates appropriate method in the generated class. this actually is simply doing things you could do yourself as well. Instead of setting the eventhandler in the designer, you can also wire the event in the constructor, or the load event handler. > In the spirit of the topic I started earlier ("yet another deriving > question") I would say that there is no need to derive from the Form. > The generated code could easily be modified to instantiate the Form > class and achieve the desired look by using its public interface. > Now, new class still must be created, if nothing else then because of > points no. 4 and 5. But there is no need for this class to be derived > from the Form. Sure you could do that, smells like the MVC pattern :) The thing is actually academic: do you want to store your form's control code how the form looks INSIDE the form class (as it belongs to that form class and to that form class alone) or do you want to store it outside the form class, which avoids a subclass but REQUIRES a separate controller class? > Benefit of such approach: > If the generated class would wrap the instance of the Form as a > private member (rather than inheriting from it), it could protect its > users from the direct dependency to the Form class. why would aggregation be of any advantage here? Overriding a simple thing like the OnClosing method of the form is in your approach a problem. > Downsides: > 1. It is hard to imagine that .NET Windows Forms developer will ever > want to use something else. and rightfully so. > 2. If the generated class is derived from the Form its users get the > usual Form public interface for free. Recall what I said, that the > Form class has large interface. This could be resolved by making the > generated class contain and return the reference to the contained > Form, but by doing this, the single benefit gets lost. So concluding, what you propose isn't that great... ? :) > This re raised some basic questions. Is polymorphism (as the VS > designer uses it) appropriate here, even though the derived class > doesn't change the behavior, but only adds new one? Which approach do > you see as preferable and why? The initially generated class which represents YOUR form doesn't use polymorphism YET, but can do that, if you want to. As you might know, a Form is actually a Control. So you can override whatever virtual property/method of Control in your own Form class to make it act differently in a piece of code which acts on Controls. It's this polymorphic behavior which makes it possible to use forms as controls in docking /sliding frames in a .NET app :) Frans -- ------------------------------------------------------------------------ Lead developer of LLBLGen Pro, the productive O/R mapper for .NET LLBLGen Pro website: http://www.llblgen.com My .NET blog: http://weblogs.asp.net/fbouma Microsoft MVP (C#) ------------------------------------------------------------------------
From: Sasa on 5 Sep 2006 07:58 "Frans Bouma" <perseus.usenet.NOSPAM.(a)xs4all.nl> wrote in message news:xn0equz4q68tnu000(a)news.xs4all.nl... > Sasa wrote: >> In .NET world, there is a class called Form which essentially >> represents a windows form (basically standard MS Windows' window). A >> Form class has fairly large interface which can be used to manipulate >> the window. This includes methods/properties such as changing window >> position/size, setting its style, back color, caption etc. as well as >> adding child controls. >> >> When designing custom form via MS Visual Studio designer, the >> corresponding C# code (if one does it in C# project of course) is >> designed which uses the aforementioned class Form and its interface >> to achieve the look created in the designer. >> >> Following are facts about generated code: >> 1. The generated code is placed in a separate class. >> 2. The class is derived from the Form class. >> 3. The generated code uses only public features of the Form class. It >> introduces no overrides. > > Why would it use overrides? The thing is: the code which makes up YOUR > form is stored in a method, called InitializeComponent. That method is > called from the constructor generated into the code which makes up your > form. > > This is done on purpose. Say, this wasn't done and InitializeComponent > was a method of the class Form, called from its empty constructor (i.e. > no parameters). > > There's no constructor generated into your form code, just an override > of the InitializeComponent method. > > Now, you create a new constructor which accepts a parameter. > Your form doesn't work anymore, as the base constructor isn't called. > > With the method generated into the empty constructor, you see you need > to call that method in the constructor. It's still not solid though, > but there's no real solution for this, other than introducing a > pre-load method which is called by the framework. This actually creates > more confusion: what happens when?, the same confusion seen with > ASP.NET forms. I never said the code must introduce overrides, and I agree with you. I just explained this for the purpose of the topic. > >> 4. For each child control added to the form >> via the designer, the appropriate member variable is added to the >> generated class. I can use this member to manipulate the child >> control in the runtime. >> 5. For each event I want to handle, the >> designer creates appropriate method in the generated class. > > this actually is simply doing things you could do yourself as well. > Instead of setting the eventhandler in the designer, you can also wire > the event in the constructor, or the load event handler. That's perfectly clear. Again, I just wanted to point out some interesting features of the generated code. >> In the spirit of the topic I started earlier ("yet another deriving >> question") I would say that there is no need to derive from the Form. >> The generated code could easily be modified to instantiate the Form >> class and achieve the desired look by using its public interface. >> Now, new class still must be created, if nothing else then because of >> points no. 4 and 5. But there is no need for this class to be derived >> from the Form. > > Sure you could do that, smells like the MVC pattern :) > The thing is actually academic: do you want to store your form's > control code how the form looks INSIDE the form class (as it belongs to > that form class and to that form class alone) or do you want to store > it outside the form class, which avoids a subclass but REQUIRES a > separate controller class? The question is what is Form class, and should the generated code be specialization of the Form, or simply its user. >> Benefit of such approach: >> If the generated class would wrap the instance of the Form as a >> private member (rather than inheriting from it), it could protect its >> users from the direct dependency to the Form class. > > why would aggregation be of any advantage here? Overriding a simple > thing like the OnClosing method of the form is in your approach a > problem. That's a downside, but I'll discuss it below. Aggregation is advantage because it decouples user of my class from the Form class. Now I might agree that it doesn't have significant practical benefit, because we are assuming that Form class has stable interface, and that existing interface will be supported in the future versions, and that there probably won't be any significant alternative to the Form class in the future (however the last one we don't know for sure). >> Downsides: >> 1. It is hard to imagine that .NET Windows Forms developer will ever >> want to use something else. > > and rightfully so. > >> 2. If the generated class is derived from the Form its users get the >> usual Form public interface for free. Recall what I said, that the >> Form class has large interface. This could be resolved by making the >> generated class contain and return the reference to the contained >> Form, but by doing this, the single benefit gets lost. > > So concluding, what you propose isn't that great... ? :) I'm not really proposing it. The idea came to my mind, but I am basically not sure which approach is more in the OO spirit. I am really trying to explore this to gain better feeling on when to use inheritance, and when not. >> This re raised some basic questions. Is polymorphism (as the VS >> designer uses it) appropriate here, even though the derived class >> doesn't change the behavior, but only adds new one? Which approach do >> you see as preferable and why? > > The initially generated class which represents YOUR form doesn't use > polymorphism YET, but can do that, if you want to. As you might know, a Of course it could. But the way I understand polymorphism - its purpose is to vary implementation while keeping the same (base) interface. If I need to override, it is another responsibility. In that case I basically want to introduce new Form which modifies the default behavior of the Form class. However, in my mind, the designer generated code doesn't modifies the behavior of the Form. It reuses the Form in order to achieve look&feel of my form. The very fact, that its code can be converted to the black box is the proof of that. What do you think? > Form is actually a Control. So you can override whatever virt
From: H. S. Lahman on 5 Sep 2006 12:19 Responding to Sasa... > The example I'm going to give is based on the .NET Windows Forms, but > it's really a design related question not related to technology. I'll > try to explain the relevant stuff to non .NET people, so if you have > patience/time read on... > > In .NET world, there is a class called Form which essentially represents > a windows form (basically standard MS Windows' window). A Form class has > fairly large interface which can be used to manipulate the window. This > includes methods/properties such as changing window position/size, > setting its style, back color, caption etc. as well as adding child > controls. > > When designing custom form via MS Visual Studio designer, the > corresponding C# code (if one does it in C# project of course) is > designed which uses the aforementioned class Form and its interface to > achieve the look created in the designer. > > Following are facts about generated code: > 1. The generated code is placed in a separate class. > 2. The class is derived from the Form class. As soon as I read this I started jumping up and down. (See below.) > 3. The generated code uses only public features of the Form class. It > introduces no overrides. I'm confused. Where does automatic code generation come into the picture? > 4. For each child control added to the form via the designer, the > appropriate member variable is added to the generated class. I can use > this member to manipulate the child control in the runtime. > 5. For each event I want to handle, the designer creates appropriate > method in the generated class. > > In the spirit of the topic I started earlier ("yet another deriving > question") I would say that there is no need to derive from the Form. I agree. The Form is (should be) primarily a data holder whose only behavior responsibility might be to talk to the OS Window manager to render the image. IOW, it is an entity from the UI problem space. In contrast, whoever understands the problem semantics of what information should actually go into the display is a quite different critter that is abstracting the customer problem space. Those entities are apples & oranges. > The generated code could easily be modified to instantiate the Form > class and achieve the desired look by using its public interface. Right. Instantiate it, invoke all the Form setters to initialize the display, and then invoke Form.doIt() to render the data. However, you only mentioned the associated controls in passing. I suspect it is not just a Form instance that needs to be created; you will also need to create associated Control instances as well. IOW, I suspect there is need of some sort of factory object here to get everything done. The segues to application partitioning. If the UI is complex, the problem space entity that knows what information to display would likely be in a different subsystem. It would make a display request with a bundle of data to the UI subsystem interface. Within the UI subsystem some sort of factory object would field that request and do the actual instantiation and initialization. Only that factory object would understand Form and its associated Controls. IOW, the problem space entity thinks in terms of "display account" but the UI thinks in terms of "create forms and controls". The factory object provides the mapping of the message from the customer space entity to forms and controls. > Now, new class still must be created, if nothing else then because of > points no. 4 and 5. But there is no need for this class to be derived > from the Form. > > Benefit of such approach: > If the generated class would wrap the instance of the Form as a private > member (rather than inheriting from it), it could protect its users from > the direct dependency to the Form class. Uh oh. I am concerned you have now created a god object as your "generated class". Separate the concerns. Rendering a UI is a different suite of responsibilities than determining what needs to be rendered. Let whoever decides what needs to be rendered talk to the guy who renders on a peer-to-peer basis. Note, BTW, that if you put the customer space entity in a different subsystem than the UI entities, the subsystem interface provides all the decoupling you need (so long as it is a pure message-based data transfer interface). Because the UI subject matter is so different and requires different abstractions (Form/Control), it is pretty standard practice to encapsulate it in its own subsystem for applications with complex UIs. (A bonus in doing so is that once one abstracts the UI invariants, such a subsystem can be reusable across applications having the same sort of UI.) For simple UIs that might be overkill. If you employ some sort of factory object to create the Form and its associated Controls, that object provides a decoupling buffer. IOW, it presents a "display account" interface to the problem space entity and then proceeds to map that into the setter interface of the Form. Now the object that knows what data to display needs to know nothing about Forms and Controls. ************* There is nothing wrong with me that could not be cured by a capful of Drano. H. S. Lahman hsl(a)pathfindermda.com Pathfinder Solutions http://www.pathfindermda.com blog: http://pathfinderpeople.blogs.com/hslahman "Model-Based Translation: The Next Step in Agile Development". Email info(a)pathfindermda.com for your copy. Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php. (888)OOA-PATH
From: Frans Bouma on 6 Sep 2006 04:05 Sasa wrote: > "Frans Bouma" <perseus.usenet.NOSPAM.(a)xs4all.nl> wrote in message > news:xn0equz4q68tnu000(a)news.xs4all.nl... > > Sasa wrote: > >> In the spirit of the topic I started earlier ("yet another deriving > >> question") I would say that there is no need to derive from the > Form. >> The generated code could easily be modified to instantiate > the Form >> class and achieve the desired look by using its public > interface. >> Now, new class still must be created, if nothing else > then because of >> points no. 4 and 5. But there is no need for this > class to be derived >> from the Form. > > > > Sure you could do that, smells like the MVC pattern :) > > The thing is actually academic: do you want to store your form's > > control code how the form looks INSIDE the form class (as it > > belongs to that form class and to that form class alone) or do you > > want to store it outside the form class, which avoids a subclass > > but REQUIRES a separate controller class? > > The question is what is Form class, and should the generated code be > specialization of the Form, or simply its user. The generated code is code which you don't have to type in anymore. That's the purpose. So if you delete the generated code, you have to write the code to fill the form with controls and make the controls do things and have logic act upon actions performed by the user. Some people like to make things overly complicated and stack class upon class and create whole frameworks to display a couple of forms. To have an external controller for your form (viewer) is only sufficient if you need to re-use the controller code with other viewers as well. Often this is not the case. So the code belonging to the form is IMHO better of INSIDE the form class, for the sole reason that it belongs to that particular form class. Why else use OO? > >> Benefit of such approach: > >> If the generated class would wrap the instance of the Form as a > >> private member (rather than inheriting from it), it could protect > its >> users from the direct dependency to the Form class. > > > > why would aggregation be of any advantage here? Overriding a simple > > thing like the OnClosing method of the form is in your approach a > > problem. > > That's a downside, but I'll discuss it below. Aggregation is > advantage because it decouples user of my class from the Form class. that's just saying it does decouple them, but it doesn't explain the advantage. > Now I might agree that it doesn't have significant practical benefit, > because we are assuming that Form class has stable interface, and > that existing interface will be supported in the future versions, and > that there probably won't be any significant alternative to the Form > class in the future (however the last one we don't know for sure). it has a severe downside: you've to replicate the Form's interface in your own class, which creates MORE code, and for what? WHY do you want to make this so overly complicated? I fail to see it. Software development isn't getting better by making things complicated. > >> Downsides: > >> 1. It is hard to imagine that .NET Windows Forms developer will > ever >> want to use something else. > > > > and rightfully so. > > > >> 2. If the generated class is derived from the Form its users get > the >> usual Form public interface for free. Recall what I said, that > the >> Form class has large interface. This could be resolved by > making the >> generated class contain and return the reference to the > contained >> Form, but by doing this, the single benefit gets lost. > > > > So concluding, what you propose isn't that great... ? :) > > I'm not really proposing it. The idea came to my mind, but I am > basically not sure which approach is more in the OO spirit. I am > really trying to explore this to gain better feeling on when to use > inheritance, and when not. that's simple. Only use inheritance if you want to create a specialized type of an existing type. So YOUR form is a specialized type of the existing type Form: you add specific code to it. If you're not doing that, you don't need inheritance. > >> This re raised some basic questions. Is polymorphism (as the VS > >> designer uses it) appropriate here, even though the derived class > >> doesn't change the behavior, but only adds new one? Which approach > do >> you see as preferable and why? > > > > The initially generated class which represents YOUR form doesn't use > > polymorphism YET, but can do that, if you want to. As you might > > know, a > > Of course it could. But the way I understand polymorphism - its > purpose is to vary implementation while keeping the same (base) > interface. If I need to override, it is another responsibility. In > that case I basically want to introduce new Form which modifies the > default behavior of the Form class. However, in my mind, the > designer generated code doesn't modifies the behavior of the Form. adding code to a form is also changing behavior: you add behavior, so the behavior isn't THE SAME as the superclass: the superclass' behavior is a subset of the subclass' behavior IN THAT CASE (i.e. you don't override a single method). > It > reuses the Form in order to achieve look&feel of my form. The very > fact, that its code can be converted to the black box is the proof of > that. What do you think? I think you should let go the VB6 way of thinking and use what's done for you and you should try to avoid to make everything more complicated than it is. Good code is simple, readable, understandable maintainable code which does what it should do. Complicated complex code which also does what it should do is IMHO bad code. > > It's this polymorphic behavior which makes it possible to use forms > > as controls in docking /sliding frames in a .NET app :) > > AFAIK most of the methods/properties of the Control class and its > derivatives are not virtual. Most of the virtual methods are the > OnXXX methods which do nothing more than fireing of the events. I'm > trying to figure out is this a good example of the polymorphism? Do > you consider this to be good design of the code? Microsoft's guidelines say that a method or property should only be virtual if there's a solid use-case scenario available which requires that that method is virtual so the class is extensible
|
Next
|
Last
Pages: 1 2 Prev: Abstract public member variales? Next: what's the future of Object Oriented Programming |