I'm stuck on this concept.
This is part of an explanation I saw on a site:
Hiding the Implementation
A primary consideration in object-oriented design is separating the things that change from the things that stay the same.
This is particularly important for libraries. Users (client programmers) of that library must be able to rely on the part they use, and know that they won't need to rewrite code if a new version of the library comes out. On the flip side, the library creator must have the freedom to make modifications and improvements with the certainty that the client code won't be affected by those changes.
This can be achieved through convention. For example, the library programmer must agree to not remove existing methods when modifying a class in the library, since that would break the client programmer's code. The reverse situation is thornier, however. In the case of a field, how can the library creator know which fields have been accessed by client programmers? This is also true with methods that are only part of the implementation of a class, and not meant to be used directly by the client programmer. But what if the library creator wants to rip out an old implementation and put in a new one? Changing any of those members might break a client programmer's code. Thus the library creator is in a strait jacket and can't change anything.
But I can't imagine a real situation where this can happen.
Can someone show me a practical example of this in real life?
This is how I imagine this:
public void print(String message)
{
System.out.println(message);
}
What difference does it make if a library client knows this implementation or not?
The implementation is not really hidden from view. Especially since most libraries out there that you will use are open source. "Hidden", in this case, refers to anything that is not part of the public API. The public API of a library consists of the public methods and fields that a library exposes. Once a library releases a version, it should continue to support the public API on future versions. Anything else is considered hidden and users of that library cannot rely on that "hidden code" being there in future version of that library.
EDIT:
But how could the client rely on code if it was not hidden, for example?
So lets say that a library comes out with a method that looks like this
public void doSomething(CharSequence x);
This is considered not hidden because it is public. Me as a user of that method is expecting it to exist in future versions of that library. So I am expecting that the input to that method is a CharSequence. If the author of that library wants to change that to String then that would be wrong. They should not change that CharSequence to a String because the users of the previous version are expecting CharSequence and switching it to a String might have negative consequences when the previous users of the library upgrade to the new version. In this case, the code might not compile.
So basically, if it is not hidden (aka part of the public API) then the author should not make any changes to the public API that would make previous versions of the library to not work.
This comes up all the time and there are ways around it. For example, when log4j upgraded to version 2, their changes were so dramatic that their API had to break and hence created a whole new library called log4j 2. So its a completely different library with different package names. It is not a new version of the old library, its a new library with similar name.
As a contrast to that, take a look at the Java SE's HashTable class. This is old class that should not be used anymore. But Java has a strict rule that the old public API of previous versions must still be supported in new versions. So Java cannot do what log4j did.
Another example is Spring. Spring tries to follow the approach that Java did, in that you only need to update the version and your old code should work. But Spring does deprecate parts of its public API. It will remove old classes and methods that are public but that it really does not want people to use anymore. In this case, me as a user of Spring might find it hard to upgrade from version 1 to version 4, for example. Mainly because some of the public API might have been deprecated.
So here I have given three different ways library writers have tackled this situation.
1) Side steps the old version and create a whole new library. E.g. Log4j.
2) Be strict and always support old public AIP's. E.g. Java.
3) Slowly deprecate old public API methods or classes. E.g. Spring.
Me as a user of these libraries would prefer that old public API be supported. I have used all three of those examples. I have had to work with old HashTable classes on legacy code I was upgrading to Java 8 and was happy that it was still supported. I have felt the pain of upgrading from log4j 1 to log4j 2. I have also upgraded Spring on a complicated project and have had adverse affects that needed to be troubleshooted. I can tell you that being strict to your old public API's is easiest on the users of said library.
There are many examples in the real world for this. For instance, if you consider buying a grocery previously v/s buying a grocery now. Or building a house previously v/s building a house now.
As time goes on the implementation changes of anything, but still the end result is same like bought grocery or built house. So, the library must have methods like buyGrocery() or buildHouse(), the implementation of which keeps on changing, but the user of the library still calls the same methods to attain the end results. Hope this answered your query.
Cheers!
Say for example, you're working with a LinkedList of names, and you make a utility method to print all the names in the list:
public void print(LinkedList<String> names)
{
for (String name : names)
System.out.println(name);
}
This works, but it limits you to only using a LinkedList. What if for some reason, some other code that you have runs slowly with a LinkedList, so you change it to an ArrayList? Well, now you have to go and change this method too.
public void print(ArrayList<String> names)
{
for (String name : names)
System.out.println(name);
}
But within this method, it doesn't matter if it is a LinkedList or an ArrayList, as long as you can iterate over it. This is where you want to hide the implementation details from your code, by using an interface:
public void print(Iterable<String> names)
{
for (String name : names)
System.out.println(name);
}
Now, you don't even have to pass in a List - you could pass in a HashSet, and it would still work. So, from your original qoute:
A primary consideration in object-oriented design is separating the things that change from the things that stay the same
The things that change, in this case, would be how you iterate over the collection, represented by the ArrayList and LinkedList implementations.
The thing that stays the same is the fact that you can iterate over the collection, which is what the Iterable interface represents.
A simple example could be if a log method was used for logging errors. Maybe first all it did was print to the console. Then later you wanted to write errors to a file:
public void log(String message)
{
// write to file
}
Then later you decided to write to a database or make a remote call:
public void log(String message)
{
// make network call
}
As long as the implementation is hidden, clients can continue calling log() and nothing will break because you did not change the method signature.
You can also have multiple implementations of this method by extracting an interface, as shown by #tima.
Related
I know enums are used when we are expecting only a set of values to be passed. We don't want the caller to pass anything other than the well defined set.
And this works very well inside a project. Because you know what you've to pass.
But consider 2 projects, I am using the models of 1st project in 2nd.
Second project has a method like this.
public void updateRefundMode(RefundMode refundMode)
enum RefundMode("CASH","CARD","GIFT_VOUCHER")
Now, I realise RefundMode can be PHONEPE also, So If I start passing this to 1st project, it would fail at their end (Unable to desirialize enum PHONEPE). Although I've added this enum at my end.
Which is fine, because If my first project doesn't know about the "PHONEPE", then it doesn't know how to handle it, so he has to update the models too.
But my problem is, Let's imagine a complex Object am trying to pass, which also takes this RefundMode, when I pass a new RefundMode just this field should be become null or ignored at their end right ? Rather than not accepting the whole object, and breaking the entire flow/request.
Is there a way I can specify jackson (jsonproperties) to just ignore that field if an unknown value is being passed. Curious to know.. (Although In that case, I am breaking the rule of ENUM) So, why not keep a String which solves all the problem ?
It's all about contracts.
When you are in a client/server situation, being a mobile app and a web server, or a Java library (jar) and another Java project, you have to keep the contracts in mind.
As you observed, a change in contracts need to be propagated to both parties: the client and the server (supplier).
One way of working with this is to use versioning. You may say: "Version 1: those are the refund modes.". Then the mobile app may call the web server by specifying the contract version in the URL: /api/v1/refund?mode=CASH
When the contract needs to be changed, you need to consider what to do with the clients. In the case of mobile apps, the users might not have updated their app to the latest version, so their app may still be calling /api/v1 (and not supporting new refund modes). In that case, you may want to support both /api/v1 and /api/v2 (with the new refund mode) in your web server.
As your example shows, it is not always possible to transparently adapt one contract version to another (in your example, there is no good equivalent to PHONEPE in the original enum). If you have to deal with contract updates, I suggest explicitly writing code to them (you can use dedicated JSON schemas, classes and services) instead of trying to bridge the gaps. Think of what would happen with a third, fourth version.
Edit: to answer your last question, you can ignore unknown fields in JSON by following this answer (with the caveats explained above): https://stackoverflow.com/a/59307683/2223027
Edit 2: in general, using Enums is a form of strong typing. Sure, you could use Strings, or even bits, but then it would be easier to make mistakes, like using GiftVoucher instead of GIFT_VOUCHER.
I have a class in a Java Library(open-m3u) that I need to change just slightly.
The functionality is easy to implement on my own without using the library. The library is open-source so i have access to all of its code. The class is made in such a way that inheriting it or even changing that small part is not possible. My question is should I copy that class and all the classes that it depends on and put them in my own code base and change the functionality or should implement the functionality myself. Or is there another option?
The functionality is easy to implement on my own without using the
library.
IMHO, then that's the way to go. Your other options are:
Build the functionality around the library: you say that's not possible in your case.
Create a branch of the library in your own source control system. That means you'll have to keep that repository in sync with the library maintainers, which means a permanent burden. And you have to check what the library's license says about forking.
Copy the relevant parts into your code base and do the modifications there. Then you won't profit from future enhancements or bug fixes, but still have to maintain code that was created and architected by someone else, and doesn't exactly fit your requirements. And you have to check what the library's license says about copying parts into a foreign code base.
They all have their drawbacks.
As a general remark: in 25 years of professional software development, I've seen both successful usages of external libraries as well as complete failures. Some times, we invested more time into evaluating existing libraries (and then finding out that nothing matched) than we needed for implementing the project-specific solution on our own.
And every library you can do without, makes config management and rollout easier.
Decorator pattern allows you to add new functionality to existing object.
If java library you use has any class like this:
public class LibraryClass implement ILibraryInterface {
public void someMethod() {
...
}
}
Then you can create Decorator class:
public class LibraryClassDecorator implement ILibraryInterface {
private LibraryClass libObj;
public LibraryClassDecorator(LibraryClass libObj) {
this.libObj = libObj;
}
public void someMethod() {
libObj.someMethod();
// here you can do whatever you want.
// Add some additional logic
// transform result value if there is some
}
}
Note: you have to implement the same interface to follow Liskov substitution principle
A solution will be to make a class that extends the one you wanna change and overide the part you wanna change
We have a product with standard functionality and our clients also customize the product to their requirements. But currently they make changes in the core product code.
I want to know the approaches that can be used to make a j2EE application extensible or customizable.
To elaborate this, read below:
for example: consider below class:
Class A{
public void doSomething(Object o){
// standard product functionality goes here.
// due to client customizations. client code also goes here.
}
}
In above class, client has added the code to the core product code. Ideally the product code should not be modified based on open-closed principle.
Currently we dont directly allow client to add code in the method but provide customization points as below.
Class A{
public ClassAExtension ext;
public void doSomething(Object o){
// standard product functionality goes here.
// client code goes in doClientCustomizations();
ext.doClientCustomizations(Object o);
}
}
So now client uses "ClassAExtension" class to override the behaviour. However, this approach is still not that elegant and makes the product code more cluttered with such customization points.
What different approaches or frameworks are available to do such things in a more elegant and efficient way?
First thing you should do is to clearly separate the code being the standard product and the extensions by using separate packages and deployment artefacts (so having a JAR for your core and a JAR for the extensions).
Sticking to basic Java mechanisms, you could for example specify hook methods in your component, which don't do anything by default, but could be overridden by an customized component extending the core component.
A small side note: Don't use the term J2EE anymore if not having to maintain ancient applications.
After some research I cannot come across the best approach for this. There will be certain color classes that I would like to share amongst multiple projects. Let's call one of them EncryptedColor. Since it is used across multiple projects I don't want multiple copies of it in existence of course. Otherwise I would need to make sure that an update in one location would need to be updated everywhere. However, these classes are needed in some released SDKs that we provide to customers.
How could I design it such that I can use these classes but not provide them with the classes that they don't need access to from their SDK. I don't want useless classes to become visible and flood the smaller subset of classes that they really need to be seeing.
A couple approaches I have thought of so far but aren't quite ideal:
Try and use a doclet structure that hides the calls within the javadoc such as doclava. Javadoc has not fully implemented its own hiding mechanism yet. As I understand this doesn't keep the functions from being visible, but it was mentioned in one spot that you would need reflection to use the calls. I don't see how just the javadoc does that so I must have been missing something.
Android has designed themselves it seems to force reflection from some #hide attributes included in methods that they have in source code. But from the sounds of it, the system hides those and then uses a different jar when it is loading to make those visible at launch time. Probably not useful here.
If I were to keep shared classes in the same package name I could access default and protected members, but...then I am keeping all my classes that use these in the same package name. Not quite ideal either, but it could be done in that manner if I needed to. Might get out of hand with large quantities of shared resources.
What approaches are taken typically in situations such as these? I haven't liked my findings and thought process thus far.
Short answer : you can't hide/remove these classes as they are needed at runtime by your application.
In my opinon, you have 3 alternatives :
Change the classes access to "package private". Yes, doing that doesn't make it impossible to access them, but these classes won't be accessible directly.
Remove the classes and create an API. You want to hide the logic ? Remove it and provide it through a REST API for instance. Depending or your architecture, it could be difficult or impossible.
Create all the instance of these classes in a dynamic way, with Class.forName, using Spring or as in #Steve K answer, with Java's ServiceLoader. As a result, you will be able to remove these classes from the main jar and make them more private, in a way. Again, classes will be here but a little less accessible.
My suggestion that could work would be to implement your color classes as a service using the Java ServiceLoader
You make an interface for your color classes, and implementations can be called using the ServiceLoader class. Then you simply separate your color classes into two packages - a public package you can jar up and distribute with your SDK, and a private package for those classes you want to be internal. The ServiceLoader will find all the color classes available so long as the jar files are in your project's classpath.
For example, if your color classes (as an example) had a common interface like this:
public interface MyAppColor {
public int getRed();
public int getGreen();
public int getBlue();
public int getAlpha();
public void setRed(int red);
public void setGreen(int green);
public void setBlue(int blue);
public void setAlpha(int alpha);
public boolean isValid();
public void doSomething(Object arg);
}
Then you could have a bunch of implementing classes in a jar file, with a service descriptor file included in the jar at the path:
META-INF/services/com.my.app.MyAppColor
The text of that file is simply the list of classes in the jar that implement the interface - one per line:
com.my.app.MyPublicAppColor
com.my.app.MyEncryptedPublicAppColor
com.my.app.MyOtherPublicAppColor
etc. Then all you have to do is make a factory for instantiating the correct type, which could be as simple as this:
public class MyAppColorFactory {
private static ServiceLoader<MyAppColor> serviceLoader = ServiceLoader.load(MyAppColor.class, null);
public static MyAppColor get(String className){
if (className != null){
for (MyAppColor c : serviceLoader){
if (className.equals(c.getClass().getName())){
return c;
}
}
}
return null;
}
}
Deploying only needed code:
- Use Only The Needed Source In Development (1) (2)
Since you have an entire library and many deployments which each use different components, the easiest way to do what you suggest is to use only the sources that you need; not a single library. You can ignore the unused sources. This will only ship the needed code.
- Make The Library "Package Private"
This will allow the access only for the public components of the library and everything else will not be callable. But, it will still ship all the code.
- Create an API as a REST SDK
This will require web access, not desirable for performance code {any code really}. You will ship no sdk code with this method.
- Obfuscate the code
Easy with the correct tools. Obfuscation will change the class and method names in production code to gibberish. This will make the library basically unusable to anyone but you. This will ship all the code but it will be obfuscated
- Native API
You can compile java to machine code and use it in production or as the api. You can also create the api in a native language {not desirable}.
I'm using Java 1.7. I have a class "ItemFactory" inside a .jar that allows other developers to create Item objects (item has a private constructor). The factory requires some user input to create certain items. Recently I added some items which also require input, but all the necessary data is already present in the system. I thought it would be esier for developers to let my "ItemHandler" class automatically create these items. So instead having them type this:
ItemFactory factory = new ItemFactory();
Item item = factory.createItem(parameter1, parameter2);
ItemHandler handler = new ItemHandler();
handler.doSomethingCool(item);
They could simply do this:
handler.doSomethingCool()
and the doSomethingCool() method will make the item automatically from the factory because all necessary input is already present in the system.
My problem is now that the facotry class suddenly has public methods that should not be visible. For example, the public method createItemForSomethingCoolPurposes(), is automatically invoked by the system itself and developers needed worry about it. It's potentially confusing for them to see this method because it's not clear what its purpose is. Adding comments/documentation to express "this method should not be called" seems stupid. Am I wrong on this? Is this a common problem, and are there conventions about it?
Simply refactor those methods using the old code which is no longer public. If you can't do so because you don't have control over the code using your api mark those methods #Deprecated and add a note that in the next version it will be removed. So you simply need to communicate your intention to remove the public methods and after everyone refactored their code you can remove the code.
This is what the developers of the java sdk are doing as well. They mark obsolete code #Deprecated add a link and an example to the new code and remove the obsolete code in the next release.
You could probably refactor the method to be package-private.
https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
For more info on the topic, read Effective Java (3rd ed):
ITEM 15: MINIMIZE THE ACCESSIBILITY OF CLASSES AND MEMBERS
Alternatively using Google's error-prone library you could annotate it with #DoNotCall and also add a #Deprecated annotation so IDE users get immediate feedback that they should not call that method.