|
|
Effectively, what I'm trying to do is compartmentalize the Application class in subclasses that each have their own functionality, but are inherently tied to the Application class and are meaningless outside of it. I could pack all of Graphic's functionality inside the Application class but that would cause a lot of clutter. |
A similar metaphor would be a Car class, which has 4 members of the type Wheel, a member of the type Engine and so forth. Objects manipulating the Car class would have to be able to manipulate its Engine and Wheels as well, ideally without cluttering Car's public interface and without breaking encapsulation. |
|
|
"Program to an 'interface', not an 'implementation'." (Gang of Four 1995:18) |
Bizarre! Can't we conclude the OP's idea doesn't work. |
Bizarre! Can't we conclude the OP's idea doesn't work. |
Keep it simple. I would start by just making the members public. As you get further into the development process, you may find a reason to change this, but you might not. And if you make them private now, you may find that you have to jump through hoops later on. |
Isn't the OP's idea just doing the same thing that other GIU libraries do, such as QT? |
There are several benefits to be obtained from restricting access to a data structure to an explicitly declared list of functions. For example, any error causing a Date to take on an illegal value (for example, December 36, 2016) must be caused by code in a member function. This implies that the first stage of debugging – localization – is completed before the program is even run. This is a special case of the general observation that any change to the behavior of the type Date can and must be effected by changes to its members. In particular, if we change the representation of a class, we need only change the member functions to take advantage of the new representation. User code directly depends only on the public interface and need not be rewritten (although it may need to be recompiled). |
41. Make data members private, except in behaviorless aggregates (C-style structs) Summary They're none of your caller's business: Keep data members private. Only in the case of simple C-style struct types that aggregate a bunch of values but don't pretend to encapsulate or provide behavior, make all data members public. Avoid mixes of public and nonpublic data, which almost always signal a muddled design. Discussion Information hiding is key to good software engineering. Prefer making all data members private; private data is the best means that a class can use to preserve its invariants now, and to keep preserving them in the face of future changes. Public data is bad if a class models an abstraction and must therefore maintain invariants. Having public data means that part of your class's state can vary uncontrollably, unpredictably, and asynchronously with the rest of its state. It means that an abstraction is sharing responsibility for maintaining one or more invariants with the unbounded set of all code that uses the abstraction, and that is obviously, fundamentally, and indefensibly flawed. Reject such designs outright. ... Nonprivate data members are almost always inferior to even simple passthrough get/set functions, which allow for robust versioning. Examples Example 1: Proper encapsulation. Most classes (e.g., Matrix, File, Date, BankAccount, Security) should have all private data members and expose adequate interfaces. Allowing calling code to manipulate their internals directly would directly work against the abstraction they provide and the invariants they must sustain. Example 2: ... Example 3: Getters and setters. If there is no better domain abstraction available, public and protected data members (e.g., color) can at least be made private and hidden behind get and set functions (e.g., GetColor, SetColor); these provide a minimal abstraction and robust versioning. Using functions raises the level of discourse about "color" from that of a concrete state to that of an abstract state that we are free to implement as we want: We can change to an internal color encoding other than int, add code to update the display when changing color, add instrumentation, and make many other changes without breaking calling code. ... |
I've decided to split up the application's functionality into separate classes which handle a portion of the functionality. |