Skip to main content
added 112 characters in body
Source Link
Doval
  • 15.5k
  • 3
  • 46
  • 59

It's a symptom of a limitation in Java/C#'s module systems.

In principle, there's no reason you shouldn't be able to swap out one implementation of a class for another with the same constructor and method signatures. There are languages that allow this. However, Java and C# insist that every class have a unique identifier (the fully qualified name) and the client code ends up with a hard-coded dependency on it.

You can sort of get around this by fiddling with the file system and compiler options so that com.example.Foo maps to a different file, but this is surprising and unintuitive. Even if you do so, your code is still tied to only one implementation of the class. I.e. If you write a class Foo that depends on a class MySet, you can choose an implementation of MySet at compile time but you still can't instantiate Foos using two different implementations of MySet.

This unfortunate design decision forces people to use interfaces unnecessarily to future-proof their code against the possibility that they'll later need a different implementation of something, or to facilitate unit testing. This isn't always feasible; if you have any methods that look at the private fields of two instances of the class, won't be able to implement them in an interface. That's why, for example, you don't see union in Java's Set interface. Still, outside of numeric types and collections, binary methods aren't common, so you can usually get away with it.

Of course, if you call new Foo(...) you still have a dependency on the class, so you need a factory orif you want a dependency injection frameworkclass to pass yoube able to instantiate an unknown implementation of the interface directly. However, it's usually a better idea to accept the instance in the constructor and let someone else decide which implementation to use.

It's up to you to decide if it's worth bloating your codebase with interfaces and factories. On the one hand, if the class in question is internal to your codebase, refactoring the code so that it uses a different class or an interface in the future is trivial; you could invoke YAGNI and refactor later if the situation arises. But if the class is part of the public API of a library you've published, you don't have the option of fixing the client code. If you don't use an interface and later need multiple implementations, you'll be stuck between a rock and a hard place.

It's a symptom of a limitation in Java/C#'s module systems.

In principle, there's no reason you shouldn't be able to swap out one implementation of a class for another with the same constructor and method signatures. There are languages that allow this. However, Java and C# insist that every class have a unique identifier (the fully qualified name) and the client code ends up with a hard-coded dependency on it.

You can sort of get around this by fiddling with the file system and compiler options so that com.example.Foo maps to a different file, but this is surprising and unintuitive. Even if you do so, your code is still tied to only one implementation of the class. I.e. If you write a class Foo that depends on a class MySet, you can choose an implementation of MySet at compile time but you still can't instantiate Foos using two different implementations of MySet.

This unfortunate design decision forces people to use interfaces unnecessarily to future-proof their code against the possibility that they'll later need a different implementation of something, or to facilitate unit testing. This isn't always feasible; if you have any methods that look at the private fields of two instances of the class, won't be able to implement them in an interface. That's why, for example, you don't see union in Java's Set interface. Still, outside of numeric types and collections, binary methods aren't common, so you can usually get away with it.

Of course, if you call new Foo(...) you still have a dependency on the class, so you need a factory or a dependency injection framework to pass you an unknown implementation of the interface.

It's up to you to decide if it's worth bloating your codebase with interfaces and factories. On the one hand, if the class in question is internal to your codebase, refactoring the code so that it uses a different class or an interface in the future is trivial; you could invoke YAGNI and refactor later if the situation arises. But if the class is part of the public API of a library you've published, you don't have the option of fixing the client code. If you don't use an interface and later need multiple implementations, you'll be stuck between a rock and a hard place.

It's a symptom of a limitation in Java/C#'s module systems.

In principle, there's no reason you shouldn't be able to swap out one implementation of a class for another with the same constructor and method signatures. There are languages that allow this. However, Java and C# insist that every class have a unique identifier (the fully qualified name) and the client code ends up with a hard-coded dependency on it.

You can sort of get around this by fiddling with the file system and compiler options so that com.example.Foo maps to a different file, but this is surprising and unintuitive. Even if you do so, your code is still tied to only one implementation of the class. I.e. If you write a class Foo that depends on a class MySet, you can choose an implementation of MySet at compile time but you still can't instantiate Foos using two different implementations of MySet.

This unfortunate design decision forces people to use interfaces unnecessarily to future-proof their code against the possibility that they'll later need a different implementation of something, or to facilitate unit testing. This isn't always feasible; if you have any methods that look at the private fields of two instances of the class, won't be able to implement them in an interface. That's why, for example, you don't see union in Java's Set interface. Still, outside of numeric types and collections, binary methods aren't common, so you can usually get away with it.

Of course, if you call new Foo(...) you still have a dependency on the class, so you need a factory if you want a class to be able to instantiate an interface directly. However, it's usually a better idea to accept the instance in the constructor and let someone else decide which implementation to use.

It's up to you to decide if it's worth bloating your codebase with interfaces and factories. On the one hand, if the class in question is internal to your codebase, refactoring the code so that it uses a different class or an interface in the future is trivial; you could invoke YAGNI and refactor later if the situation arises. But if the class is part of the public API of a library you've published, you don't have the option of fixing the client code. If you don't use an interface and later need multiple implementations, you'll be stuck between a rock and a hard place.

added 43 characters in body
Source Link
Doval
  • 15.5k
  • 3
  • 46
  • 59

It's a symptom of a limitation in Java/C#'s module systems.

In principle, there's no reason you shouldn't be able to swap out one implementation of a class for another with the same constructor and method signatures. There are languages that allow this. However, Java and C# insist that every class have a unique identifier (the fully qualified name) and the client code ends up with a hard-coded dependency on it.

You can sort of get around this by fiddling with the file system and compiler options so that com.example.Foo maps to a different file, but this is surprising and unintuitive. Even if you do so, your code is still tied to only one implementation of the class. I.e. If you write a class Foo that depends on a class MySet, you can choose an implementation of MySet at compile time but you still can't instantiate Foos using two different implementations of MySet.

This unfortunate design decision forces people to use interfaces unnecessarily to future-proof their code against the possibility that they'll later need a different implementation of something, or to facilitate unit testing. This isn't always feasible; if you have any methods that look at the private fields of two instances of the class, you'rewon't be able to implement them in trouble - that'san interface. That's why, for example, you don't see union in Java's Set interface. Still, outside of numeric types and collections, binary methods aren't common, so you can usually get away with it.

Of course, if you call new Foo(...) you still have a dependency on the class, so you need a factory or a dependency injection framework to pass you an unknown implementation of the interface.

It's up to you to decide if it's worth bloating your codebase with interfaces and factories. On the one hand, if the class in question is internal to your codebase, refactoring the code so that it uses a different class or an interface in the future is trivial; you could invoke YAGNI and refactor later if the situation arises. But if the class is part of the public API of a library you've published, you don't have the option of fixing the client code. If you don't use an interface and later need multiple implementations, you'll be stuck between a rock and a hard place.

It's a symptom of a limitation in Java/C#'s module systems.

In principle, there's no reason you shouldn't be able to swap out one implementation of a class for another with the same constructor and method signatures. There are languages that allow this. However, Java and C# insist that every class have a unique identifier (the fully qualified name) and the client code ends up with a hard-coded dependency on it.

You can sort of get around this by fiddling with the file system and compiler options so that com.example.Foo maps to a different file, but this is surprising and unintuitive. Even if you do so, your code is still tied to only one implementation of the class. I.e. If you write a class Foo that depends on a class MySet, you can choose an implementation of MySet at compile time but you still can't instantiate Foos using two different implementations of MySet.

This unfortunate design decision forces people to use interfaces unnecessarily to future-proof their code against the possibility that they'll later need a different implementation of something, or to facilitate unit testing. This isn't always feasible; if you have any methods that look at the private fields of two instances of the class, you're in trouble - that's why you don't see union in Java's Set interface. Still, outside of numeric types and collections, binary methods aren't common, so you can usually get away with it.

Of course, if you call new Foo(...) you still have a dependency on the class, so you need a factory or a dependency injection framework to pass you an unknown implementation of the interface.

It's up to you to decide if it's worth bloating your codebase with interfaces and factories. On the one hand, if the class in question is internal to your codebase, refactoring the code so that it uses a different class or an interface in the future is trivial; you could invoke YAGNI and refactor later if the situation arises. But if the class is part of the public API of a library you've published, you don't have the option of fixing the client code. If you don't use an interface and later need multiple implementations, you'll be stuck between a rock and a hard place.

It's a symptom of a limitation in Java/C#'s module systems.

In principle, there's no reason you shouldn't be able to swap out one implementation of a class for another with the same constructor and method signatures. There are languages that allow this. However, Java and C# insist that every class have a unique identifier (the fully qualified name) and the client code ends up with a hard-coded dependency on it.

You can sort of get around this by fiddling with the file system and compiler options so that com.example.Foo maps to a different file, but this is surprising and unintuitive. Even if you do so, your code is still tied to only one implementation of the class. I.e. If you write a class Foo that depends on a class MySet, you can choose an implementation of MySet at compile time but you still can't instantiate Foos using two different implementations of MySet.

This unfortunate design decision forces people to use interfaces unnecessarily to future-proof their code against the possibility that they'll later need a different implementation of something, or to facilitate unit testing. This isn't always feasible; if you have any methods that look at the private fields of two instances of the class, won't be able to implement them in an interface. That's why, for example, you don't see union in Java's Set interface. Still, outside of numeric types and collections, binary methods aren't common, so you can usually get away with it.

Of course, if you call new Foo(...) you still have a dependency on the class, so you need a factory or a dependency injection framework to pass you an unknown implementation of the interface.

It's up to you to decide if it's worth bloating your codebase with interfaces and factories. On the one hand, if the class in question is internal to your codebase, refactoring the code so that it uses a different class or an interface in the future is trivial; you could invoke YAGNI and refactor later if the situation arises. But if the class is part of the public API of a library you've published, you don't have the option of fixing the client code. If you don't use an interface and later need multiple implementations, you'll be stuck between a rock and a hard place.

Better wording and formatting.
Source Link
Doval
  • 15.5k
  • 3
  • 46
  • 59

It's a symptom of a limitation in Java/C#'s module systems. 

In principle, there's no reason you shouldn't be able to swap out one implementation of a class for another one with the same constructor and method signatures; there aresignatures. There are languages that allow this. However, Java and C# insist that every class have a unique identifier (the fully-qualified qualified name), and the client code of the class ends up with a hard-coded dependency toon it.

You can kindasort of get around this by messingfiddling with the file system and compiler options so that com.example.Foocom.example.Foo maps to a different file, but the users of your code will hatethis is surprising and unintuitive. Even if you for itdo so, and your code is still hard-codedtied to only one implementation of the class. eI.ge. If you write a class Bar uses someFoo that depends on a class FooMySet, you can play file system tricks to choose an implementation of a FooMySet at compile time, but you won't be able to have twostill can't instantiate BarFoos using two different implementations of FooMySet.

This unfortunate design decision meansforces people need to lean on interfacesuse interfaces unnecessarily to future-proof their code against the possibility that they'll later need a different implementation of something, or to facilitate unit testing. This isn't always feasible -feasible; if you have any binary methods that look at the private fields of two instances of the class, you're screwed. That'sin trouble - that's why you don't see union in Java's Set interface. But mostStill, outside of the timenumeric types and collections, binary methods aren't common, so you can usually get away with it.

Of course, if you call new Foo(...) you still have a hard-coded dependency on the classclass, so you need a factory or a dependency injection framework to pass you an unknown implementation of the interface.

It's up to you to decide if it's worth bloating your codebase with all these interfaces and factories. On the one hand, if the class in question is internal to your codebase, refactoring the code so that it uses a different class or an interface in the future is fairly trivialtrivial; you could invoke YAGNI and refactor later if the situation arises. But if it'sthe class is part of the public API of a library you've published, you don't have the option of fixing the client code, so. If you may want to future-proof the codedon't use an interface and later need multiple implementations, you'll be stuck between a rock and a hard place.

It's a symptom of a limitation in Java/C#'s module systems. In principle, there's no reason you shouldn't be able to swap out one implementation of a class for another one with the same constructor and method signatures; there are languages that allow this. However, Java and C# insist that every class have a unique identifier (the fully-qualified name), and the client code of the class ends up with a hard-coded dependency to it.

You can kinda get around this by messing with the file system and compiler options so that com.example.Foo maps to a different file, but the users of your code will hate you for it, and your code is still hard-coded to one implementation of the class. e.g. If class Bar uses some class Foo, you can play file system tricks to choose a Foo at compile time, but you won't be able to have two Bars using two different implementations of Foo.

This unfortunate design decision means people need to lean on interfaces unnecessarily to future-proof their code against the possibility that they'll later need a different implementation of something, or to facilitate unit testing. This isn't always feasible - if you have any binary methods that look at the private fields of two instances of the class, you're screwed. That's why you don't see union in Java's Set interface. But most of the time, you can get away with it.

Of course, if you call new Foo you still have a hard-coded dependency on the class, so you need a factory or a dependency injection framework to pass you an unknown implementation of the interface.

It's up to you to decide if it's worth bloating your codebase with all these interfaces and factories. On the one hand if the class in question is internal to your codebase, refactoring the code so that it uses a different class or an interface in the future is fairly trivial. But if it's part of the public API of a library you've published, you don't have the option of fixing the client code, so you may want to future-proof the code.

It's a symptom of a limitation in Java/C#'s module systems. 

In principle, there's no reason you shouldn't be able to swap out one implementation of a class for another with the same constructor and method signatures. There are languages that allow this. However, Java and C# insist that every class have a unique identifier (the fully qualified name) and the client code ends up with a hard-coded dependency on it.

You can sort of get around this by fiddling with the file system and compiler options so that com.example.Foo maps to a different file, but this is surprising and unintuitive. Even if you do so, your code is still tied to only one implementation of the class. I.e. If you write a class Foo that depends on a class MySet, you can choose an implementation of MySet at compile time but you still can't instantiate Foos using two different implementations of MySet.

This unfortunate design decision forces people to use interfaces unnecessarily to future-proof their code against the possibility that they'll later need a different implementation of something, or to facilitate unit testing. This isn't always feasible; if you have any methods that look at the private fields of two instances of the class, you're in trouble - that's why you don't see union in Java's Set interface. Still, outside of numeric types and collections, binary methods aren't common, so you can usually get away with it.

Of course, if you call new Foo(...) you still have a dependency on the class, so you need a factory or a dependency injection framework to pass you an unknown implementation of the interface.

It's up to you to decide if it's worth bloating your codebase with interfaces and factories. On the one hand, if the class in question is internal to your codebase, refactoring the code so that it uses a different class or an interface in the future is trivial; you could invoke YAGNI and refactor later if the situation arises. But if the class is part of the public API of a library you've published, you don't have the option of fixing the client code. If you don't use an interface and later need multiple implementations, you'll be stuck between a rock and a hard place.

Source Link
Doval
  • 15.5k
  • 3
  • 46
  • 59
Loading