Related
After reading about SOLID in a few places, I was having trouble mapping between explanations with different vocabularies and code. To generalize a bit, I created the diagrams below, and I was hoping that people could point out any 'bugs' in my understanding.
Of course, feel free to reuse/remix/redistribute as you'd like!
I think your diagrams look quite nice, but I'm afraid that I couldn't understand them (particularly the interface one), so I'll comment on the text.
It's not really clear to me what you mean by layer, in the Open/closed I thought you might mean interface, but the interface and dependency items suggest you don't mean that.
Open/closed : actually your text from the Liskov item is closer to describing open/closed. If the code is open for extension, we can make use of it (by extending it) to implement new requirements, but by not modifying the existing code (it's closed for modification) we know we wont break any existing code that made use of it.
"Only depend on outer layer" - if this means only depend on an interface not the implementation, then yes, that's an important principle for SOLID code even though it doesn't map directly to any of the 5 letters.
Dependency inversion uses that but goes beyond it. A piece of code can make use of another via its interface and this is has great maintainability benefits over relying on the implementation, but if the calling code still has the responsibility for creating the object (and therefore choosing the class) that implements the interface then it still has a dependency. If we create the concrete object outside the class or method and pass it in as an interface, then the called code no longer depends on the concrete class, just the interface
void SomeFunction()
{
IThing myIthing* = new ConcreteThing();
// code below can use the interface but this function depends on the Concrete class
}
void SomeFunctionDependencyInjectedVersion(IThing myIthing*)
{
// this version should be able to work with any class that implements the IThing interface,
// whether it really can might depend on some of the other SOLID principles
}
Single responsibility : this isn't about classes intersecting, this is about not giving a code more than one responsibility. If you have a function where you can't think of a better name than doSomethingAndSomethingElse this might be a sign its got more than one responsibility and could be better if it was split (the point I'm making is about the "and" in the name even when the "somethings" are better named).
You should try to define that responsibility so that the class can perform it entirely, (although it make may use of other classes that perform sub-responsibilities for it) but at each level of responsibility that a class is defined it should have one clear reason to exist. When it has more than one it can make code harder to understand, and changes to code related to one responsibility can have unwanted side-effects on other responsibilities.
Iterface segregation: Consider a class implementing a collection. The class will implement code to add to the collection or to read from it. We could put all this in one interface, but if we separate it then when we have consuming code that only needs to read and doesn't need to add to the collection then it can use the interface made of the reading methods. This can make the code clearer in that it shows quickly that the code only needs those methods, and, if we've injected the collection by interface we could also use that code with a different source of items that doesn't have the ability to add items
(consider IEnumerable vs ICollection vs IList)
Liskov substitution is all about making sure that objects that inherit from an interface/base class behave in the way that the interface/base class promised to behave. In the strictest interpretation of the original definition they'd need to behave exactly the same, but that's not all that useful. More generally its about behaving in a consistent and expected way, the derived classes may add functionality, but they should be able to do the job of the base objects (they can be substituted for them)
"Code to interfaces" is considered good practice. Such code is easy to unit test and enables loose coupling. Users only know the interfaces and the onus of wiring concrete objects is upon the top-most level (this can be done in some init code or with the help of frameworks).
My question is about following the practice of code to interfaces: does it imply that a concrete class can never declare any public method which is not present in its interface?
Otherwise, it will force users to depend upon the concrete implementation. This will make such methods difficult for unit testing; if the test fails, determining if it failed due to an issue in the caller code or due to the concrete method will require extra effort. This will also break the Dependency Inversion Principle. It will induce type-checking and down-casting, which are considered bad practice.
That is totally acceptable provided that the new methods aren't crucial to the operating of the class, and in particular to how it functions when someone thinks of it as the superclass or interface.
ArrayList provides good examples. It has methods that let you manage its internal memory, like ensureCapacity(int) or trimToSize(). Those are sometimes helpful if you know you're working with an ArrayList and need to be more precise about memory allocation, but they're not required for the basic operation of the ArrayList, and in particular, they're not required for having it operate as a general List.
In fact, interfaces themselves can add new methods in this way. Consider NavigableSet, which extends Set. It adds a whole bunch of methods that rely on the ordering of the set's elements (give me the first, the last, a subtree starting from here, etc). None of those methods are defined on Set, and even the fact that the elements are ordered isn't defined by the Set contract; but the Set methods all work just fine without the additional methods and ordering.
The advice to "code to the interface" is a good start, but it's a bit over-generalized. A refinement of that advice would be, "code to the most general interface that you need." If you don't need ArrayLists's methods (or its contract, such as its random-access performance), code to List; but if you do need them, then by all means use them.
#yshavit's third paragraph hits it right. Implement an extension of the "not enough" base interface, as exampled with public interface NavigableSet<E> extends SortedSet<E> (which, BTW, extends Set<E> extends Collection<E> extends Iterable<E>).
It's his second paragraph that troubles me. Why have "non-crucial" methods of the API that are not surfaced in some interface being implemented? In the ArrayList example, why not have the size management methods declared in an interface? Perhaps ManagedSize which would describe clear behavior for ArrayList (and other) classes to implement, along with the several other interfaces it implements (my JRE source says: public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable).
With such an approach, there is no need to decide which methods are "non-crucial," only to be surprised by some client code that depends on things like ensureSize to help avoid relocation during a time-critical phase, or trimToSize to release excessive overalloaction when it's algorthmically known that further growth will not be needed. Not that I'm promoting such algorthms as best practice, but even non-functional "behavior management" methods deserve their place in the light.
Finally, while I agree with sentiment of "Know Where the Lines Are, and yet Color As You See Fit" it doesn't give practical guidance. Here's attempt at such:
Always start by coding to an interface, ie. all concrete public methods should be declared in an interface:
Use multiple interfaces as needed
Each interface should partition the implemented API into coherent non-overlapping aspects, e.g. List, RandomAccess, Cloneable, Serializable
Tend to start with larger scoped interfaces and break them up as the design develops (before coding ala Waterfall, or as code evolves ala Agile); interfaces are one of the easier design artefacts to refactor.
If a given interface you are implementing is "insufficient":
Extend the base interface and add the methods you need, then implement that one, OR
Create an augmenting interface (like the ManagedSize idea, above) with just the additional methods and then implement them both
Only when you find you can't do that, then relax only as much of the rule as you need to make things work (often, this will be an experimental trial-error "does it work, yet?" cycle).
Reasons for #3's "can't" will vary, but I expect them to be external to the application design, e.g. the ORM I'm using becomes confused, the IDE plug-in doesn't refactor it correctly, the DSL translator I'm forced to use fails when a class implements more than three interfaces...
I just came across Inversion of Control approach (implemented using Dependency Injection) of designing loosely coupled software architecture. As per my understanding the IOC approach aims to solve problem related to tight coupling between classes by instantiating an object of a class inside another class which should ideally not happen (as per the pattern). Is my understanding correct here?
If above is true than what about composition or has-a relationship (the very basic important aspect of OO). For an example I write my stack class using a linked list class already defined so I instantiate a linked list class inside my stack class. But as per IOC this will result in tight coupling and hence a bad design. Is this true? I am bit confused here between composition or has-a relationship and IOC.
As per my understanding the IOC approach aims to solve problem related
to tight coupling between classes by instantiating an object of a
class inside another class which should ideally not happen (as per the
pattern). Is my understanding correct here?
Close, but you are slightly off. The problem of tight coupling is addressed when you define contracts between classes (interfaces in Java). Since you need implementations of your contracts(interfaces), at some point those implementations must be provided. IoC is one way of providing an implementation, but not the only way. So tight coupling is really orthogonal to Inversion of Control (meaning it's not directly related).
More specifically, you can have loose coupling but no IoC. The IoC part is that the implementations are coming from outside of the components. Consider the case where you define a class that uses an interface implementation. When you test that class, you might provide a mock. When you pass the mock to the class under test, you are not using IoC. However when you start your app, and the IoC container decides what to pass to your class, that's the IoC.
For an example I write my stack class using a linked list class
already defined so I instantiate a linked list class inside my stack
class. But as per IOC this will result in tight coupling and hence a
bad design. Is this true? I am bit confused here between composition
or has-a relationship and IOC.
Yes and No. In the general sense, you don't need to completely abstract every bit of functionality in your app. You can, and purists probably would, but it can be tedious and over-done.
In this case, you could treat your stack as a black box, and not manage it with IoC. Remember, the Stack itself is loosely couple because the Stack's behavior can be abstracted away. Also, consider the following two definitions
class StackImpl implements Stack {
private List backingList
vs
class StackImpl implements Stack {
private LinkedList backingList
The first is vastly superior to the second, precisely because it's easier to change List implementations; i.e. you have already provided a loose coupling.
That's as far as I would take it. Besides, if you are using composition, you can certainly configure most IoC containers (if not all) to pass things to the constructor or invoke setters, so you can still have a has-A relationship.
Good implementations of IoC can fulfill the "has a" pattern, but just abstract the implementation of the child.
For example, every business layer class may, by your design, "have a" exception handler; with IoC you can define it so that the exception handler that actually gets instantiated at runtime be different in different environments.
The most value in IoC is if you are doing lots of automated testing; in these scenarios you can instantiate mock data access components in your test environment, but have real data access components instantiated in production, which keeps your tests clean. The downside of IoC is that it's harder to debug, since everything is more abstract.
I have my doubts as to my understanding of Inversion of Control too. (It seems like an application of good OO design principles given a fancy name) So, let me assume you are a beginner, analyse your example and clarify my thoughts on the path.
We should start by defining an interface IStack.
interface IStack<T>
{
bool IsEmpty();
T Pop();
void Push(T item);
}
In a way we are already finished; the rest of the code probably will not care whether we implemented it with linked lists, or arrays, or whatever. StackWithLinkedList : IStack and StackWithArray : IStack will behave the same.
class StackWithLinkedList<T> : IStack<T>
{
private LinkedList<T> list;
public StackWithLinkedList<T>()
{
list = new LinkedList<T>();
}
}
So StackWithLinkedList totally owns the list; it does not need any help from outside to construct it, it does not need any flexibility (that line will never change) and the clients of StackWithLinkedList couldn't care less (they have no access to the list). In short, this is not a good example to discuss Inversion of Control: we don't need any.
Let's discuss a similar example, PriorityQueue<T> :
interface IPriorityQueue<T>
{
bool IsEmpty();
T Dequeue();
void Enqueue(T item);
}
Now we have a problem: we need to compare items of type T to provide an implementation of a IPriorityQueue. Clients still do not care whether we use an array, or a heap or whatever inside, but they do care about how we compare items. We could require T to implement IComparable<T> but that would be an unnecessary restriction. What we need is some piece of functionality that will compare T items by our request:
class PriorityQueue<T> : IPriorityQueue<T>
{
private Func<T,T,int> CompareTo;
private LinkedList<T> list;
//bla bla.
}
Such that:
if CompareTo(left,right) < 0 then left < right (in some sense)
if CompareTo(left,right) > 0 then left > right (in some sense)
if CompareTo(left,right) = 0 then left = right (in some sense)
(We would also require CompareTo to be consistent, etc. but that's another topic)
The problem is how to initialize CompareTo.
One option might be, -let's suppose there is a generic comparison creator somewhere- use the comparison creator. (I agree, the example is becoming a little silly)
public PriorityQueue()
{
this.CompareTo = ComparisonCreator<T>.CreateComparison();
this.list = new LinkedList<T>();
}
Or, perhaps even something like: ServiceLocator.Instance.ComparisonCreator<T>.CreateComparison();
This is not an ideal solution for the following reasons:
PriorityQueue is now (very unnecessarily) dependant on ComparisonCreator. If it is on a different assembly, it has to reference it. If someone changes ComparisonCreator he has to make sure PriorityQueue is not affected.
The clients will have a difficult time to use the PriorityQueue. They will first need to make sure that the ComparisonCreator is constructed and initialized.
The clients will have a difficult time to change the default behaviour. Suppose somewhere a client needs a different CompareTo function. There is no easy solution. For example, if it changes the ComparisonCreator<T>'s behaviour, it may affect other clients. What if there are other threads. Even in a single thread environment the client will probably need to undo the change on construction. It's too much effort just to make it work.
For the same reasons, it is difficult to unit test the PriorityQueue. One needs to set up the whole environment.
Of course, - and of course you knew this all along - there is a much easier way in this specific problem. Just provide the CompareTo function in the constructor:
public PriorityQueue(Func<T,T,int> CompareTo)
{
this.CompareTo = CompareTo;
this.list = new LinkedList<T>();
}
Let's check:
PriorityQueue is independent of ComparisonCreator.
For the clients, probably it is much easier to use PriorityQueue. They may need to provide a CompareTo function, but at the worst case they can always ask the ServiceLocator, so al least it is never more difficult.
Changing the default behaviour is very easy. Just give a different CompareTo function. What one client does, does not affect other clients.
It is very easy to unit test PriorityQueue. There is no complex environment to set up. We can easily test it with different CompareTo functions, etc.
What we did is called "constructor injection" because we injected a dependency in the constructor. By giving the needed dependency at the construction, we were able to change the PriorityQueue into a "self sufficient" class. We still create a LinkedList<T>, a concrete class in the construction for the same reasons in Stack example: it is not a real dependency.
The tight coupling in your stack example comes from the stack intantiating a specific list type. The IOC allows the creator of the stack type to provide which exact list implementation to use (e.g. for performance or testing purposes), realizing that the stack does not (at least should not) care what the exact type of the list is as long as it has a specific interface (the methods that stack wants to use) and the concetere implementation provides the required semantics (e.g. iterating through the list will give access to all elements added to the list in the order they were added).
As per my understanding the IOC approach aims to solve problem related
to tight coupling between classes by instantiating an object of a
class inside another class which should ideally not happen (as per the
pattern). Is my understanding correct here?
IoC is actually quite a broad concept, so let's restrict the field to the Dependency Injection approach that you are referring to. Yes, Dependency Injection does what you said.
I think the reason why hvgotcodes thinks that you are slightly off is that the concept of tight coupling can be thought as of having multiple levels. Programming to interfaces is the way to abstract from a particular implementation, which keeps the usage of some piece of code some client code interacts with and its implementation loosely coupled.
The implementation has to be created (instantiated) somewhere though: even if you program to an interface, if the implementation is created inside the client code you are bound to that particular implementation.
So we can abstract the implementation from the interface, but we can also abstract the choice of which implementation to use.
As soon as this detail is clear, you have to ask yourself when it makes sense to abstract the choice of the implementation, which is basically one of the fundamental questions of software engineering: when should you abstract what? The answer to the question is of course context dependent.
But as per IOC this will result in tight coupling and hence a bad
design. Is this true?
If tight coupling is bad design, why are you still relying on standard Java classes? We actually need to distinguish between stable and volatile dependencies.
Citing your example, if you are using the standard implementation of a list, you probably may not want to inject this dependency into your class. What would you achieve by doing this? Do you expect the standard implementation of the list to change any time soon, or do you want to be able to inject a different implementation of a standard list?
On the other hand, suppose you have a custom list with some sort of change tracking mechanism, so that you can perform undo and redo operations on it. Now it could make sense to inject it, because you may want to be able to unit test the client class in isolation, without incurring in potential bugs of your custom list implementation.
As you see, tight coupling is not always bad, sometimes it makes sense, sometimes it is to be avoided: in the end it comes down to the type of dependency.
I was wondering, I recently read an article that spoke of the ills of using the singleton pattern siting the disadvantage of global variable occurrence and rightly that the singleton violates alot of the rules we learn from OOP school, single responsibility principle, programming to interfaces and abstract classes and not to concrete classes... all that good stuff. I was wondering how then do you work with like database connection class where you want just one connection to your DB and one object of your DB floating around. The author spoke of Dependency Injection principle which to my mind stands well with the Dependency Inversion rule. How do I know and control what object gets passed around as a dependency other than the fact that I created the class and expect everyone using it play nice and make sure they are using the right resource?!
Edit: This answer assumes you are using a dependency injection container, either one you wrote yourself, or one you got from a library. If not, then use a DI container :)
How do I know and control what object gets passed around as a dependency other than the fact that I created the class and expect everyone using it play nice and make sure they are using the right resource?!
By contract
The oral contract - You write a design spec that says "thou shalt not instantiate this class directly" and "thou shalt not pass around any object you got from the dependency injection container. Pass the container if you have to".
The compiler contract - You give them a dependency injection container, and they grab the instance out of it, by abstract interface. If you want only a single instance to be used, you can supply them a named instance, which they extract with both the name, and the interface.
ISomething instance = serviceLocator.ResolveInstance<ISomething>(
"TheInstanceImSupposedToUse");
You can also make all your concrete classes private/internal/what-have-you, and only provide them an abstract interface to operate against. This will prevent them from instantiating the classes themselves.
// This can only be instantiated by you, but can be used by them via ISomething
private class ConcreteSomething : ISomething
{
// ...
}
By code review
You make group-wide coding and design standards that are fair, and make sure they are understood by everyone within the group.
You use a source control mechanism, and require code reviews before they check in. You read over their code for what they link to, what headers they include, what objects they instantiate, and what instances they are passing around.
If they violate your rules during code reviews, you don't let them check in until they fix their code. Optionally, for repeat offenders, you make them pay you a dollar, you make them buy you lunch, or you hire a different contractor to replace them. Whatever works well within your group :)
For those who criticize the singleton pattern, based on SRP, here is an opposing view. Also, I've found that dependency injection containers can create as many problems as they solve. That said, I'm using a promising compromise, as covered in another post.
Dependency injection containers (even one you develop yourself, which isn't an entirely uncommon practice) are generally very configurable. What you'd do in that scenario is configure it such that any request for the interface that implementation, well, implements would be satisfied with that implementation. Even if it's a singleton.
For example, take a look at the Logger singleton being used here: http://www.pnpguidance.net/News/StructureMapTutorialDependencyInjectionIoCNET.aspx
Don't take what you read anywhere as absolute truth. Read it, understand it and then you can see when it's best to apply certain things. In your case, why wouldn't you want to create a static singleton?
What are the different types of encapsulation?
Am I right in thinking this basically refers to central OO concepts such as Abstraction, Polymorphism and Inheritance?
My understanding of encapsulation is that it is a method of hiding data / functionality, but I never really considered Polymorphism or Inheritance a form of encapsulation, although I can see how polymorphism could be considered encapsulation as it can hide the exact type of the object you are interacting with.
So, would you say that's about it, or am I missing some core concepts?
edit I just noticed in the comments someone mentioned it could refer to private / public methods, perhaps I'm thinking in to the question too much and expecting a more complicated answer than it really is?
You're thinking too much I think.
http://en.wikipedia.org/wiki/Information_hiding
Excerpt from this article:
Information hiding in computer science is the principle of hiding of design decisions in a computer program that are most likely to change, thus protecting other parts of the program from change if the design decision is changed. The protection involves providing a stable interface which shields the remainder of the program from the implementation (the details that are most likely to change).
One common form of encapsulation is using properties to hide private data fields. An even more common form is the use of OO to encapsulate the complexity of software into well divisoned classes with roles and responsibilities. This is a key tennant of OO, as it moves from a monolithic procedural design style to a more structured style which strives to hide all irrelevant information except that which pertains to the particular task your working on.
It is my view and understanding that the term encapsulation (to encapsulate) is the art/science of capturing the essence of something for the purpose of display. In fact, by definition - to encapsulate is to package something or enclose it in another container. Therefore the term encapsulation would mean to take the essence of what you are attempting to achieve and packaging it in a useful form so that it can be reused as necessary.
So to interpret this, it would mean to package material in a form that would make it more useful later.
So really...interpret this as you see fit. I see it as taking a bunch of algorithms and utilities and creating a class structure that can be used as an API in other projects. This encapsulated code could be inherited and/or extended to make it useful for modified purposes without changing the underlying essence of the API.
Therefore, abstraction, polymorphism and inheritance aren't forms of encapsulation, but forms of extending and modifying encapsulated code.
Different forms of encapsulation would mean the modifiers on properties, methods, fields and classes - that is public, private, static, virtual (in C#). Everything else (i.e. overloads, overrides, shadows) is a modification or an extension to that encapsulation.
You may consider the modified code an encapsulation which could then be further inherited/abstracted/extended, but the package which is to be extended is the encapsulated product.
Encapsulation is defined by the International Organisation for Standardization's International Standard: "Information technology – Open Distributed Processing," ISO/IEC 10746, 1998.
It's defined in terms of more primitive definitions:
Entity: Any concrete or abstract thing of interest.
Object: A model of an entity. An object is characterised by its behaviour and,
dually, by its state.
Behaviour (of an object): A collection of actions with a set of constraints on
when they may occur.
Interface: An abstraction of the behaviour of an object that consists of a
subset of the interactions of that object together with a set of constraints
on when they may occur.
Encapsulation: the property that the information contained in an object is
accessible only through interactions at the interfaces supported by the
object.
The ISO does not define different types of encapsulation.
Other posts have mentioned information hiding. The ISO does not define encapsulation explicitly in terms of information hiding, though it does seem implicit, see "Encapsulation theory fundamentals," at http://www.edmundkirwan.com/pub/
Ed.
Encapsulation is more than simply information hiding. That is one aspect of it. It has to do with the interface to a module. An interface provides two very important functions: encapsulation and abstraction.
Abstraction is when a client of a module does not need to know more than what is in the interface.
and
Encapsulation is when a client of a module isn't able to know more than what is in the interface.
(Both definitions from Using UML by Perdita Stevens)
Since encapsulation simply refers to "information hiding" then I would imagine that a lot of things can be categorized as encapsulation. However I tend to think of encapsulation as "implementation hiding", in other words it is a tool that I use to create loose coupling between anything I write and anything client of what I have written.
So I tend to believe, pragmatically, that encapsulation is any paradigm or best-practice that allows me to present a clean, solid interface to any client.
Generally the usage of the word is pretty close to what it says. You encapsulate something when you contain it, and don't let any of the deals loose. The best way to think about it is that you are taking something and putting it into a black-box where no one can see the details anymore. The box hides everything, providing some other disassociated interface in its place.
Information hiding is just one aspect of encapsulation, since along with the data you can also hide any of the details of the code itself. The purpose of encapsulating a part of your system is to draw that bit of complexity away from the whole, thus making it easier to understand the separate details (on both sides). More?
Paul.
"Candidate Definitions for Encapsulation:
Physically grouping together related operations or things.
GateKeeper of state or data.
Hiding implementation."
Sourced from: Encapsulation Definition
There are two parts/ways to achieve Encapsulation:
First, encapsulation is a technique that packages related data and behaviors into a single unit, i.e, Physical grouping of operations(behaviors)
E.g.:-
class Person {
String name;
int age;
void talk() {
}
void think() {
}
void work() {
}
void play() {
}
}
Second, encapsulation is a technique for protecting data from misuse by the outside world, which is referred as ‘information hiding’ or ‘data hiding’.
E.g.:-
class Person {
private String name;
private int age;
public String getName() {
return name;
}
public String getAge() {
return age;
}
}
Sourced from: What is Encapsulation in Java - the WHAT, WHY and HOW, spoiler author cites Interface as an example, which is not true. Interface are for Abstraction