I have read several books and listen to lecture regarding software design.
But I don't know how to resolve problems caused by following OO design priciples.
Here is some situation.
I start to design simple single class (ClassA).
After that, ClassA grows up with similar responsibilities.
According to Single Responsibility Priciple, I extract some logic from ClassA to ClassB.
ClassA becomes simple enough again.
However, a responsibility of ClassA maybe similar with a responsibility of ClassB,
so that ClassA and ClassB have references each other as member fields or properties to cooperate.
In other words, seperation of classes make another complexity. That is a interaction between seperated classes.
Fromafter, each of ClassA and ClassB may also grows up with more complex responsibilites,
and some classes(ClassC or ClassD) may be seperated from ClassA or ClassB.
Now, interactions between classes become much more complex.
Each of classes may have references to other classes as memeber fields or method parameters.
As single class become simpler, number of classes increase, complexity of relationship and interaction between classes also increase.
In some fortunate case, it could be solved by design patterns.
In many case, however, seperation of classes make relationship of classes more complex.
and make tendency to generate classes having too many references to other classes as members.
A class having too many references to other classes as members is hard to test.
I have read several OO design books. Most of them talk that simple class is good.
None of them, however, focus on complexity of classes interaction caused by SRP.
Do I miss something?
How can I resolve this problem?
The responsibility means one reason to change.
You may need to change the class A due to one reason, and you probably accidentally change the behavior of another responsibility in class A. Sometime you just need one of functionality of class A to use or to test, but you need to create a whole class A.
If you don't separate class A into class A, B, C, and D, the interactions between the responsibilities still exist but hidden in the class A.
To make classes more coherent and the interactions more explicit would let your code more maintainable.
I think it's not ok to think about the srp in terms of class size. I think you should think about actors and reasons to change.
Actors are roles that would want to change your class. For example if you have a class like this:
class User
{
public function calculatePay()
public function save()
}
Two different roles would want to change your class. For example, an accountant would want to change the calculatePay method, and a DB administrator would want to change the save() method. This class could change for two different reasons.
I think it's better to think of the srp in terms of "Grouping together things that change for the same reason."
Related
From what I've read and what I've seen, I consider multiple inheritance as a bad practice, not by itself but because it leads beginner to use everywhere where more elegant design patterns might be useful and more meaningful.
Some languages have chosen not to implement multiple inheritance and then have chosen to implement traits (e.g. PHP). The only interesting and substantial difference I see between multiple inheritance and traits I see is a linguistic one: while "inheritance" indicates some kind of shared nature, "trait" stands more for features.
Is there any other important difference I'm missing that would explain why some consider that multiple inheritance was inappropriate and that, now, traits are appropriate?
You could use traits to fake multiple inheritance, but I believe the basic difference is a conceptual one. A parent-child relation is a "is-a" relation.
If you have a Furniture class, with a Table child and a PicknickTable child, you have Picknicktable is-a Table is-a Furniture (hmm, is furniture countable like that? nvrmnd).
With traits, you just say: I hate to keep on writing the code to put stuff on a surface, so I write the "putStuffOnThisThing" trait, and they have it. This is not inheritance! The basic fault behind such reasoning might be is that you want to look at traits as a different way to show hierarchies while you shouldn't. It is no substitution for an actual good design, it is a trick in the toolbox that you could misuse for multiple inheritance, but you might be better use as a way to avoid writing some lines several times.
So in defence of the comparison: traits have some of the same problems as multiple inheritance, like the problem you need to address with aliasing in case of multiple things with the same name. While this is not exactly the diamond problem, it comes awfully close.
Abstract example: If I have a system with domains of "Fleet" containing a "Vehicle" class, and "Customers" containing a "Driver" class, where would you place a joining class (which would detail lifecycle, insurance claims, and other information about the relationship)? Fleet and Customer concerns are equally important to the system and views on the relationship from both directions will be made.
Fleet.DriverHistory?
Customers.VehicleHistory?
MyVagueGeneralRelationshipNamespace.VehicleDriverHistory?
Other?
I don't think it needs to be a Vague relationship. The vehicle allocations may be "abstract" in the sense that you can't touch them, but in a business sense they are "real", in fact they are pretty much the whole reason for the business. So I'd have a domain "Rental" or some such, which can have your two histories.
I think some kind of record class independent of both two classes is definitely the way to go, ie
MyVagueGeneralRelationshipNamespace.VehicleDriverHistory
I have a GUI tool that manages state sequences. One component is a class that contains a set of states, your typical DFA state machine. For now, I'll call this a StateSet (I have a more specific name in mind for the actual class that makes sense, but this name I think will suffice for the purpose of this question.)
However, I have another class that has a collection (possibly partially unordered) of those state sets, and lists them in a particular order. and I'm trying to come up with a good name for it - not just for internal code, but for customers to refer to it.
The role of this particular second collection is to encapsulate the entire currently used/available collection of StateSets that the user has created. All of the StateSets will be used eventually in the application. A good analogy would be a hand of cards versus the entire table: The 'table' contains all of the currently available hands, while the 'hand' contains a particular collection of cards.
I've got these as starter ideas I could throw out for the class name; I'm not comfortable with either at the moment:
Sequence (maybe...with something else tacked on to the name)
StateSetSet (reasonable for code, but not for customers)
And as ewernli mentions, these are really technical terms, which don't really convey a the idea well. Any other suggestions or ideas?
Sequence - Definitely NOT. It's too generic, and doesn't have any real semantic meaning.
StateSetSet - While more semantically correct, this is confusing. You have a sequence, which implies order, which is different from a set, which does not.
That being said, the best option, IMO, is StateSetSequence, as it implies you have a sequence of StateSet instances.
What is the role/function of you StateSetSet?
StateSetSet or Sequence are technical terms.
Prefer a term that convey the role/function of the class.
That could well be something like History, Timeline, WorldSnapshot,...
EDIT
According to your updated description, StateSet looks to me like StateSpace (the space of all possible states). If the user can then interactively create something, it might be appropriate to speak of a Workspace. If the user creates various state spaces of interest, I would then go for StateSpaceWorkspace. Isn't that a cool name :)
"StateSets" may be sufficient.
Others:
StateSetList
StateSetLister
StateSetListing
StateSetSequencer
I like StateSetArrangement, implying an ordering without implying anything about the underlying storage mechanisms.
I have a class A that has a collection of objects of Class B.
Class A can also 'inherit' (for lack of a better term) the collection of objects of Class B from other instances of Class A. To model this, instances of Class A point to other instances of Class A (I control for circular references).
A simplified concrete example might be that a person has biological children but also 'inherits' children from their spouse and ex-spouses.
I use instances of class A with and without the inherited objects in my application at run-time. That is, both 'projections' of instances of Class A are meaningful to me in the context of my application in difference scenarios.
My question is, is there a pattern for coding this sort of model or standard terminology? I don't think 'inherit' is the right word here. I have my own ways of handling it technically and my own cumbersome terminology but I'm imagining there is a standard pattern I can adhere to that I just can't seem to find.
An imperfect analogue would be inspecting the methods of .NET classes with and without their inherited methods or inspecting prototypes in Javascript, but here I'm 'inheriting' records/objects.
Looks like the composite pattern to me, with A objects being composites and B leafs. The one object A that points to other objects A is a root item. The difference seems that when getting leaf items you distinguish whether the root item includes leaf items from other composites it knows of or not.
No, I don't think (A) there are common OOP idioms for what you're doing, nor (B) any prominent patterns similar to yours. And (C), that is absolutely fine. Now maybe you should be doing it this way and maybe you shouldn't be. Whenever you're doing something that you have a hard time describing, you should certainly second-guess yourself and wonder if there's a simpler way of doing it. But, the lack of common terminology for describing your model, and it not fitting into a "pattern" you've heard of, does not in itself indicate a problem. Classes sometimes have to do wacky stuff under the hood. That's the point. If you're encapsulating a lot of complexity for the consumers of these classes, and it's intuitive and logical and discoverable for them, then great!
It is a mistake though to improperly use common terms to try to help someone understand. In fact, your use of the term inherit above really confused me, and I'm still not 100% sure I have it. Is it this?
An object of class ClassA maintains a collection of ClassB objects. In addition, some of a ClassA object's functionality has to act upon not only its own ClassB objects, but those maintained by other ClassA objects as well. A ClassA object maintains references to other ClassA objects for this purpose.
Assuming I have it correct of course, I think that's a good way to decribe it. And since there is precisely no inheritance here, it would confuse people if that term were used. Also, do not ever, ever, every be distressed if what you're doing does not match some pattern somewhere.
I think your model is at fault. If two or more instances of a class have a relation with an instance of another class, the correct model is not to make one of the instances contain the third - it is to make both of them refer to the third. In the case of human parents, each should refer to the same "offspring" (a list of human children) object. You then control the referred to class via mechanisms such as reference counting.
OOP defines two basic types of relationships:
A is a B
A has a B
Within the second category you have subcategories:
A contains B
B is a component of A
A is associated with (or references) B
The first two are similar, but your concrete example clearly refers to the 3rd. Parents do not contain children, they are related to their children, and when somebody marries into family, they have new relationships (associations) created with the existing family.
So I guess the answer is no, there is no "pattern." You are simply copying/transforming a set of relationships from one instance to another.
Something keeps showing up in my programming, and it is that two things are the same from some viewpoint, but different from another. Like, imagine you build a graph of rail stations, connected by trains, then the classes Vertex and RailStation are sometimes the same, other times not.
So, imagine I have a graph that very much represents rail stations and trains. Then I hand this graph to another object, which deletes some vertices, and then I want the corresponding rail stations to be gone.
I don't want to make rail stations "properties" of vertices, they're not. Also, the problem is symmetrical: If I erase a railstation, I want the corresponding vertex to be gone. What is the proper OO way to model or correspondences. I'm willing to go a few extra miles by writing some support methods or classes, if in the end the overall usage is simple and easy.
I'm currently using the Smalltalk programming language, but the question isn't really smalltalk-specific, I think. I just mention it because in Smalltalk, you can do cool tricks like examining the call stack, which might be helpful in this context.
Update:
Well, RailStations aren't Vertices! Are they?
Ok, let us consider real code, as demanded in the answers. Let me model a person with children. That's the easiest thing, right? Children should also know their parents, so we have like a doubly linked tree. To make disbanding parents from children easier, I model the link between parent and child as a Relationship, with properties parent and child.
So, I could implement parent>>removeChild: perhaps like this
removeChild: aChild
(parent relationshipWith: aChild) disband.
So, a parent has a collection of relationships, not of children. But each relationship corresponds to a child. Now I want to do things like this:
parent children removeAllSuchThat: [:e | e age < 12]
which should remove the relationship and the child.
Here, relationships and children correspond in some sense. So, what do I do now? Don't get me wrong, I'm fully aware that I could solve the problem without introducing Relationship classes. But indeed, parents and children actually do share a relationship, so why not model that and use it to help disbanding double links less imperatively?
In your problem domain, aren't stations a kind of vertex? In which case, why not derive Station from Vertex?
Notice the use of the phrase "in your problem domain". Your problem appears to be about the use as railway stations appearing in a graph. So yes, in that domain, stations are vertexes. If it was a different problem domain, say a database on railway station architecture, they may well not be. Most modern languages support some idea of namespaces to allow you to have different kinds of entity with the same names in different domains.
Regarding your parent/child problem, once again you are being too general. If I were modelling mathematical expressions and sub expressions, if I remove a parent I would want to remove and delete/free all subexpressions. OTOH, ff I were modelling legal responsibility relationships in the UK population, then when a responsibility isis dissolved (say because of a divorce), I only want to remove the relationship, and NOT delete/free the child, which has its own independent existence.
It seems like you just want RailStation to inherit from Vertex (is-a relationship). See this smalltalk tutorial on inheritance. That way, if you have a graph of RailStations, an object used to dealing (generically) with graphs of Vertexes would handle things right naturally.
If this approach won't work, be more specific (preferably with real code).
From your description of the problem, you have a one-to-one correspondence of stations to vertices and deleting a station should automatically delete the corresponding vertex (and vice-versa). You also mentioned building "a graph of rail stations, connected by trains", by which you apparently mean a graph in which stations are vertices and trains are edges.
So, in what way is a station not a vertex? If the station does not exist except as a vertex, and if a vertex does not exist except as a station, then what benefit do you see in maintaining them as two distinct-but-linked entities?
As I understand your situation, station-isa-vertex and inheritance is the way to model that.
Having a Relationship object is a good idea.
I think the appropriate question here is "which use should be made of it?".
Probably Parent and Child classes are extending the same Person superclass, so they'll have some attributes in common, age for example.
In my idea, I can see the following: Parent and Child objects have to know each other, so both classes have to keep a link to the same Relationship.
The Relationship object keeps a one-to-many relation between a single parent and a certain number of children, and it'll keep a reference to each Person object.
This way you can implement the whole disbanding logic within the Relationshp object, more or less sophisticated as you wish. You can query the Relationship object to know which members of the family match your requirements to do something. You can make the relationship to disband (and destroy) safely, as it will know all members and would ask them to break the reference and then it would be ready to destroy, or ask to some member to leave the family, keeping the Relationship object alive.
But that's not all. Relationship should be really a superclass, extended by HierarchicalRelationship and PeerRelationship (or FriendRelationship).
This specialization lets you have Parent(s) and Child(ren) to link between other hierarchies in a completely traversal way.
The true concept behind this is that your Relationship objects are the key to query and organize the whole bunch of Person objects (or Vertex objects) in a scalable and structured way, so the whole data domain you end up with is usable in any sense you like, whether you want to disband groups or walk a certain path (or railroad) between them.
Sorry for the huge amount of metaphores.
Take a look at Fame, see http://www.squeaksource.com/Fame.html
We use a specialized subclass of Collection that updates the opposite end when you add or remove elements. Also, you can annotate your classes with pragmas to annotate relations. These pragmas are used by the Fame framework to do all kind of nice stuff.