This is a general issue, but i will demonstrate it using the following problem:
I want to model airCrafts. now, for every aircraft there is one capability that is loaded with: attackCapability, IntelligenceCapability and BdaCapability. Not all aircraft can be loaded with all capabilities - every airCraft has its own potential capabilities that is supports and can be loaded with.
I want to implement this business logic with composition:
every aircraft object will hold a private member of type Capability (every capability will be implemented by a class that inherits from this abstract class/interface).
Now - I want to design a code that will enforce the business logic - i.e. will not allow any programmer to load an aircraft with an ability it doesn't support.
I have two options for doing this:
implement several overloaded version of the SetCapability() function - each one with the type of capability i want to support. For example:
public void SetCapability(AttackCapability capability);
public void SetCapability(BdaCapability capability);
That way the user can't load the aircraft with forbidden capability - and if he/she will try doing so, there will be a compilation erorr - i.e. that IDE will show some error message.
implement one function: public void SetCapability(Capability capability)
and doing some checking inside it. something like this:
public void SetCapability(Capability capability){
if(capability.getType() != typeOf(AttackCapability) || capability.getType() != typeOf(BdaCapability){
throw new InvalidOperationException();
}
_capability = capability;
}
the disdvantage here is that misuse of the user will be identified only at runtime instead at compiletime (much harder to identify and more bug prone), but as opposed to the previous option - it doesn't make you write several overloaded function which may cause the class to look heavy, strange and less readable for the inexperienced programmer.
(code reusability is not a big issues, because we always can implement private function like: private void SetCapabiltiy(Capability capability); which do the setting logic and every public overloaded SetCapability function will call it).
I feel that both option have their advantages and disadvantages as i described above.
I tend to prefer the first one, because it is more safe and hermeric - but it frequently causes my code to look "ugly" and some programmers may interprete it as duplicated code and don't understand the point...
I would like to hear your opinion for this issues, and maybe you have some better designs for this problem.
I couldn't understand your #1 option, but I think in any option you said you need to check permitted capabilities statically. This would result to change the code in future and would break the OCP. Instead of this I thought that maybe we can take advantage of dynamic dispatch here and let it to check types.
IMHO you can create final concrete classes and set required access modifiers to private in the concretes and then use factories(actually the abstract factory pattern looks suitable here) to hide object creation from clients to enforce business logic and the use the technique(which is my term) that referencing the same type used in Decorator or Chain of Responsibility patterns to keep capabilities in a chain by which you may have extra possibilities to dynamically check the capabilities to apply the behavior they require instead of just in a list( which could be used with Command pattern also)
As a note, the section where you mention as your second option limits the extensibility and generally manual type check is considered as bad practice in a dynamically dispatched or duck typed OOP language runtime. I know the fact that you are checking the field not a type but this is also a manual control and capability as the name implies is a behavior not state.
Finally since the aircrafts don't have same functionalities, but varying behaviors Visitor pattern could be used to design functionalities by which you create method classes instead of classes containing methods.
In addition, a Map<Aircraft, List<Capability>> could be used by keeping in a config object chek the features when creating objects by using DI.
//Capability types
interface Capable {
do();
}
class Attacker implements Capable {
private Capable capability;
public Attacker(Capable capability) { //to keep track of next/linked capability
this.capability = capability;
}
public do(String request) {
this.attack();
this.capability.do();//or instead of this decorator you could use chain of responsibility with next() and handle() below.
}
//to select features in some functionality.
public handle(String request) {
if ("attack".equals(request)) { //just to show what you can by keeping a reference to same type
this.attack();
} else {
this.capability.do();
}
}
public next(Capable capability) {
this.capability = capability;
}
}
class Intelligent implements Capable {
//similar to above.
}
//Aircraft types
class F111 implements Aircraft {
private Capable capability;
//or store capabilities in a list and check with config mapper object(maps aircrafts with its capabilities in a Map<Aircraft.TYPE, List<Capable> capabilities)
//private List<Capable> capabilities;
//other state
Aircraft(Capable capability) { //or create a factory
this.capability = capability;
}
//behaviors
doSth() {
this.capability.do();
}
}
class F222 implements Aircraft {
//...
}
//To hide creation of requested aircraft with only its required capabilities from the client
static class AircraftFactory { //dont permit to directly access to Aircraft concretes
static Aircraft getAircraft(String type) {//could be used abstract factory instead of this.
if("f111".equals(type)) {
return new F111(new Attacker(new Intelligent()));
}
else if(...) { new F222(new Intelligent(new Bda())}
else if(...) { new F001(new Default()) }
}
}
class Client {
main() {
//instead of this
//Aircraft f9999 = new Aircraft(new Attacker);
//f9999.doSth();
//enforce client to use factory.
Aircraft aircraft = AircraftFactory.getAircraft("f222");
aircraft.doSth();
}
}
When doing IoC, I (think that I) understand its use for getting the desired application level functionality by composing the right parts, and the benefits for testability. But at the microlevel, I don't quite understand how to make sure that an object gets dependencies injected that it can actually work with. My example for this is a BackupMaker for a database.
To make a backup, the database needs to be exported in a specific format, compressed using a specific compression algorithm, and then packed together with some metadata to form the final binary. Doing all of these tasks seems to be far from a single responsibility, so I ended up with two collaborators: a DatabaseExporter and a Compressor.
The BackupMaker doesn't really care how the database is exported (e.g. using IPC to a utility that comes with the database software, or by doing the right API calls) but it does care a lot about the result, i.e. it needs to be a this-kind-of-database backup in the first place, in the transportable (version agnostic) format, either of which I don't really know how to wrap in a contract. Neither does it care if the compressor does the compression in memory or on disk, but it has to be BZip2.
If I give the BackupMaker the wrong kinds of exporter or compressor, it will still produce a result, but it will be corrupt - it'll look like a backup, but it won't have the format that it should have. It feels like no other part of the system can be trusted to give it those collaborators, because the BackupMaker won't be able to guarantee to do the right thing itself; its job (from my perspective) is to produce a valid backup and it won't if the circumstances ain't right, and worse, it won't know about it. At the same time, even when writing this, it seems to me that I'm saying something stupid now, because the whole point of single responsibilities is that every piece should do its job and not worry about the jobs of others. If it were that simple though, there would be no need for contracts - J.B. Rainsberger just taught me there is. (FYI, I sent him this question directly, but I haven't got a reply yet and more opinions on the matter would be great.)
Intuitively, my favorite option would be to make it impossible to combine classes/objects in an invalid way, but I don't see how to do that. Should I write horrendously specific interface names, like IDatabaseExportInSuchAndSuchFormatProducer and ICompressorUsingAlgorithmXAndParametersY and assume that no classes implement these if they don't behave as such, and then call it a day since nothing can be done about outright lying code? Should I go as far as the mundane task of dissecting the binary format of my database's exports and compression algorithms to have contract tests to verify not only syntax but behavior as well, and then be sure (but how?) to use only tested classes? Or can I somehow redistribute the responsibilities to make this issue go away? Should there be another class whose responsibility it is to compose the right lower level elements? Or am I even decomposing too much?
Rewording
I notice that much attention is given to this very particular example. My question is more general than that, however. Therefore, for the final day of the bounty, I will try to summarize is as follows.
When using dependency injection, by definition, an object depends on other objects for what it needs. In many book examples, the way to indicate compatibility - the capability to provide that need - is by using the type system (e.g. implementing an interface). Beyond that, and especially in dynamic languages, contract tests are used. The compiler (if present) checks the syntax, and the contract tests (that the programmer needs to remember about) verify the semantics. So far, so good. However, sometimes the semantics are still too simple to ensure that some class/object is usable as a dependency to another, or too complicated to be described properly in a contract.
In my example, my class with a dependency on a database exporter considers anything that implements IDatabaseExportInSuchAndSuchFormatProducer and returns bytes as valid (since I don't know how to verify the format). Is very specific naming and such a very rough contract the way to go or can I do better than that? Should I turn the contract test into an integration test? Perhaps (integration) test the composition of all three? I'm not really trying to be generic but am trying to keep responsibilities separate and maintain testability.
What you have discovered in your question is that you have 2 classes that have an implicit dependency on one another. So, the most practical solution is to make the dependency explicit.
There are a number of ways you could do this.
Option 1
The simplest option is to make one service depend on the other, and make the dependent service explicit in its abstraction.
Pros
Few types to implement and maintain.
The compression service could be skipped for a particular implementation just by leaving it out of the constructor.
The DI container is in charge of lifetime management.
Cons
May force an unnatural dependency into a type where it is not really needed.
public class MySqlExporter : IExporter
{
private readonly IBZip2Compressor compressor;
public MySqlExporter(IBZip2Compressor compressor)
{
this.compressor = compressor;
}
public void Export(byte[] data)
{
byte[] compressedData = this.compressor.Compress(data);
// Export implementation
}
}
Option 2
Since you want to make an extensible design that doesn't directly depend on a specific compression algorithm or database, you can use an Aggregate Service (which implements the Facade Pattern) to abstract the more specific configuration away from your BackupMaker.
As pointed out in the article, you have an implicit domain concept (coordination of dependencies) that needs to be realized as an explicit service, IBackupCoordinator.
Pros
The DI container is in charge of lifetime management.
Leaving compression out of a particular implementation is as easy as passing the data through the method.
Explicitly implements a domain concept that you are missing, namely coordination of dependencies.
Cons
Many types to build and maintain.
BackupManager must have 3 dependencies instead of 2 registered with the DI container.
Generic Interfaces
public interface IBackupCoordinator
{
void Export(byte[] data);
byte[] Compress(byte[] data);
}
public interface IBackupMaker
{
void Backup();
}
public interface IDatabaseExporter
{
void Export(byte[] data);
}
public interface ICompressor
{
byte[] Compress(byte[] data);
}
Specialized Interfaces
Now, to make sure the pieces only plug together one way, you need to make interfaces that are specific to the algorithm and database used. You can use interface inheritance to achieve this (as shown) or you can just hide the interface differences behind the facade (IBackupCoordinator).
public interface IBZip2Compressor : ICompressor
{}
public interface IGZipCompressor : ICompressor
{}
public interface IMySqlDatabaseExporter : IDatabaseExporter
{}
public interface ISqlServerDatabaseExporter : IDatabaseExporter
{}
Coordinator Implementation
The coordinators are what do the job for you. The subtle difference between implementations is that the interface dependencies are explicitly called out so you cannot inject the wrong type with your DI configuration.
public class BZip2ToMySqlBackupCoordinator : IBackupCoordinator
{
private readonly IMySqlDatabaseExporter exporter;
private readonly IBZip2Compressor compressor;
public BZip2ToMySqlBackupCoordinator(
IMySqlDatabaseExporter exporter,
IBZip2Compressor compressor)
{
this.exporter = exporter;
this.compressor = compressor;
}
public void Export(byte[] data)
{
this.exporter.Export(byte[] data);
}
public byte[] Compress(byte[] data)
{
return this.compressor.Compress(data);
}
}
public class GZipToSqlServerBackupCoordinator : IBackupCoordinator
{
private readonly ISqlServerDatabaseExporter exporter;
private readonly IGZipCompressor compressor;
public BZip2ToMySqlBackupCoordinator(
ISqlServerDatabaseExporter exporter,
IGZipCompressor compressor)
{
this.exporter = exporter;
this.compressor = compressor;
}
public void Export(byte[] data)
{
this.exporter.Export(byte[] data);
}
public byte[] Compress(byte[] data)
{
return this.compressor.Compress(data);
}
}
BackupMaker Implementation
The BackupMaker can now be generic as it accepts any type of IBackupCoordinator to do the heavy lifting.
public class BackupMaker : IBackupMaker
{
private readonly IBackupCoordinator backupCoordinator;
public BackupMaker(IBackupCoordinator backupCoordinator)
{
this.backupCoordinator = backupCoordinator;
}
public void Backup()
{
// Get the data from somewhere
byte[] data = new byte[0];
// Compress the data
byte[] compressedData = this.backupCoordinator.Compress(data);
// Backup the data
this.backupCoordinator.Export(compressedData);
}
}
Note that even if your services are used in other places than BackupMaker, this neatly wraps them into one package that can be passed to other services. You don't necessarily need to use both operations just because you inject the IBackupCoordinator service. The only place where you might run into trouble is if using named instances in the DI configuration across different services.
Option 3
Much like Option 2, you could use a specialized form of Abstract Factory to coordinate the relationship between concrete IDatabaseExporter and IBackupMaker, which will fill the role of the dependency coordinator.
Pros
Few types to maintain.
Only 1 dependency to register in the DI container, making it simpler to deal with.
Moves lifetime management into the BackupMaker service, which makes it impossible to misconfigure DI in a way that will cause a memory leak.
Explicitly implements a domain concept that you are missing, namely coordination of dependencies.
Cons
Leaving compression out of a particular implementation requires you implement the Null object pattern.
The DI container is not in charge of lifetime management and each dependency instance is per request, which may not be ideal.
If your services have many dependencies, it may become unwieldy to inject them through the constructor of the CoordinationFactory implementations.
Interfaces
I am showing the factory implementation with a Release method for each type. This is to follow the Register, Resolve, and Release pattern which makes it effective for cleaning up dependencies. This becomes especially important if 3rd parties could implement the ICompressor or IDatabaseExporter types because it is unknown what kinds of dependencies they may have to clean up.
Do note however, that the use of the Release methods is totally optional with this pattern and excluding them will simplify the design quite a bit.
public interface IBackupCoordinationFactory
{
ICompressor CreateCompressor();
void ReleaseCompressor(ICompressor compressor);
IDatabaseExporter CreateDatabaseExporter();
void ReleaseDatabaseExporter(IDatabaseExporter databaseExporter);
}
public interface IBackupMaker
{
void Backup();
}
public interface IDatabaseExporter
{
void Export(byte[] data);
}
public interface ICompressor
{
byte[] Compress(byte[] data);
}
BackupCoordinationFactory Implementation
public class BZip2ToMySqlBackupCoordinationFactory : IBackupCoordinationFactory
{
public ICompressor CreateCompressor()
{
return new BZip2Compressor();
}
public void ReleaseCompressor(ICompressor compressor)
{
IDisposable disposable = compressor as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
public IDatabaseExporter CreateDatabaseExporter()
{
return new MySqlDatabseExporter();
}
public void ReleaseDatabaseExporter(IDatabaseExporter databaseExporter)
{
IDisposable disposable = databaseExporter as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}
public class GZipToSqlServerBackupCoordinationFactory : IBackupCoordinationFactory
{
public ICompressor CreateCompressor()
{
return new GZipCompressor();
}
public void ReleaseCompressor(ICompressor compressor)
{
IDisposable disposable = compressor as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
public IDatabaseExporter CreateDatabaseExporter()
{
return new SqlServerDatabseExporter();
}
public void ReleaseDatabaseExporter(IDatabaseExporter databaseExporter)
{
IDisposable disposable = databaseExporter as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}
BackupMaker Implementation
public class BackupMaker : IBackupMaker
{
private readonly IBackupCoordinationFactory backupCoordinationFactory;
public BackupMaker(IBackupCoordinationFactory backupCoordinationFactory)
{
this.backupCoordinationFactory = backupCoordinationFactory;
}
public void Backup()
{
// Get the data from somewhere
byte[] data = new byte[0];
// Compress the data
byte[] compressedData;
ICompressor compressor = this.backupCoordinationFactory.CreateCompressor();
try
{
compressedData = compressor.Compress(data);
}
finally
{
this.backupCoordinationFactory.ReleaseCompressor(compressor);
}
// Backup the data
IDatabaseExporter exporter = this.backupCoordinationFactory.CreateDatabaseExporter();
try
{
exporter.Export(compressedData);
}
finally
{
this.backupCoordinationFactory.ReleaseDatabaseExporter(exporter);
}
}
}
Option 4
Create a guard clause in your BackupMaker class to prevent non-matching types from being allowed, and throw an exception in the case they are not matched.
In C#, you can do this with attributes (which apply custom metadata to the class). Support for this option may or may not exist in other platforms.
Pros
Seamless - no extra types to configure in DI.
The logic for comparing whether types match could be expanded to include multiple attributes per type, if needed. So a single compressor could be used for multiple databases, for example.
100% of invalid DI configurations will cause an error (although you may wish to make the exception specify how to make the DI configuration work).
Cons
Leaving compression out of a particular backup configuration requires you implement the Null object pattern.
The business logic for comparing types is implemented in a static extension method, which makes it testable but impossible to swap with another implementation.
If the design is refactored so that ICompressor or IDatabaseExporter are not dependencies of the same service, this will no longer work.
Custom Attribute
In .NET, an attribute can be used to attach metadata to a type. We make a custom DatabaseTypeAttribute that we can compare the database type name with two different types to ensure they are compatible.
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public DatabaseTypeAttribute : Attribute
{
public DatabaseTypeAttribute(string databaseType)
{
this.DatabaseType = databaseType;
}
public string DatabaseType { get; set; }
}
Concrete ICompressor and IDatabaseExporter Implementations
[DatabaseType("MySql")]
public class MySqlDatabaseExporter : IDatabaseExporter
{
public void Export(byte[] data)
{
// implementation
}
}
[DatabaseType("SqlServer")]
public class SqlServerDatabaseExporter : IDatabaseExporter
{
public void Export(byte[] data)
{
// implementation
}
}
[DatabaseType("MySql")]
public class BZip2Compressor : ICompressor
{
public byte[] Compress(byte[] data)
{
// implementation
}
}
[DatabaseType("SqlServer")]
public class GZipCompressor : ICompressor
{
public byte[] Compress(byte[] data)
{
// implementation
}
}
Extension Method
We roll the comparison logic into an extension method so every implementation of IBackupMaker automatically includes it.
public static class BackupMakerExtensions
{
public static bool DatabaseTypeAttributesMatch(
this IBackupMaker backupMaker,
Type compressorType,
Type databaseExporterType)
{
// Use .NET Reflection to get the metadata
DatabaseTypeAttribute compressorAttribute = (DatabaseTypeAttribute)compressorType
.GetCustomAttributes(attributeType: typeof(DatabaseTypeAttribute), inherit: true)
.SingleOrDefault();
DatabaseTypeAttribute databaseExporterAttribute = (DatabaseTypeAttribute)databaseExporterType
.GetCustomAttributes(attributeType: typeof(DatabaseTypeAttribute), inherit: true)
.SingleOrDefault();
// Types with no attribute are considered invalid even if they implement
// the corresponding interface
if (compressorAttribute == null) return false;
if (databaseExporterAttribute == null) return false;
return (compressorAttribute.DatabaseType.Equals(databaseExporterAttribute.DatabaseType);
}
}
BackupMaker Implementation
A guard clause ensures that 2 classes with non-matching metadata are rejected before the type instance is created.
public class BackupMaker : IBackupMaker
{
private readonly ICompressor compressor;
private readonly IDatabaseExporter databaseExporter;
public BackupMaker(ICompressor compressor, IDatabaseExporter databaseExporter)
{
// Guard to prevent against nulls
if (compressor == null)
throw new ArgumentNullException("compressor");
if (databaseExporter == null)
throw new ArgumentNullException("databaseExporter");
// Guard to prevent against non-matching attributes
if (!DatabaseTypeAttributesMatch(compressor.GetType(), databaseExporter.GetType()))
{
throw new ArgumentException(compressor.GetType().FullName +
" cannot be used in conjunction with " +
databaseExporter.GetType().FullName)
}
this.compressor = compressor;
this.databaseExporter = databaseExporter;
}
public void Backup()
{
// Get the data from somewhere
byte[] data = new byte[0];
// Compress the data
byte[] compressedData = this.compressor.Compress(data);
// Backup the data
this.databaseExporter.Export(compressedData);
}
}
If you decide on one of these options, I would appreciate if you left a comment as to which one you go with. I have a similar situation in one of my projects, and I am leaning toward Option 2.
Response to your Update
Is very specific naming and such a very rough contract the way to go or can I do better than that? Should I turn the contract test into an integration test? Perhaps (integration) test the composition of all three? I'm not really trying to be generic but am trying to keep responsibilities separate and maintain testability.
Creating an integration test is a good idea, but only if you are certain that you are testing the production DI configuration. Although it also makes sense to test it all as a unit to verify it works, it doesn't do you much good for this use case if the code that ships is configured differently than the test.
Should you be specific? I believe I have already given you a choice in that matter. If you go with the guard clause, you don't have to be specific at all. If you go with one of the other options, you have a good compromise between specific and generic.
I know you stated that you are not intentionally trying to be generic, and it is good to draw the line somewhere to ensure a solution is not over-engineered. On the other hand, if the solution has to be redesigned because an interface was not generic enough that is not a good thing either. Extensibility is always a requirement whether it is specified up front or not because you never really know how business requirements will change in the future. So, having a generic BackupMaker is definitely the best way to go. The other classes can be more specific - you just need one seam to swap implementations if future requirements change.
My first suggestion would be to critically think if you need to be that generic: You have a concrete problem to solve, you want to backup a very specific database into a specific format. Is there any benefit you get by solving the problem for arbitary databases and arbitary formats? What you surely get of a generic solution is boilerplate code and increased complexity (people understand concrete problems, not generic ones).
If this applies to you, then my suggestion would be to not let your DatabaseExporter accept interfaces, but instead only concrete implementations. There are enough modern tools out there which will also allow you mocking concrete classes, so testability is not an argument for using interfaces here aswell.
on the other hand, if you do have to backup several databases with different strategies, then I would probably introduce something like a
class BackupPlan {
public DatabaseExporter exporter() {/**...*/}
public Compressor compressor() {/** ... */}
}
then your BackupMaker will get passed one BackupPlan, specifying which database to be compressed with which algorithm.
Your question is emphasizing the fact that object composition is very important and that the entity that is responsible for such composition (wiring) has a big responsibility.
Since you already have a generic BackupMaker, I would suggest that you keep it this way, and push the big responsibility of making sure that the right composition of objects (to solve the specific problem) is done in the composition root.
Readers of your application source code (you and your team members), would have a single place (the composition root) to understand how you compose your objects to solve your specific problem by using the generic classes (e.g. BackupMaker).
Put in other words, the composition root is where you decide on the specifics. Its where you use the generic to create the specific.
To reply on the comment:
which should know what about those dependencies?
The composition root needs to know about everything (all the dependencies) since it is creating all the objects in the application and wiring them together. The composition root knows what each piece of the puzzle does and it connects them together to create a meaningful application.
For the BackupMaker, it should only care about just enough to be able to do its single responsibility. In your example, its single (simple) responsibility (as it seems to me) is to orchestrate the consumption of other objects to create a backup.
As long as you are using DI, a class will never be sure that its collaborator will behave correctly, only the composition root will. Consider this simple and extreme example of an IDatabaseExporter implementation (assume that the developer actually gave this class this name, and that he intentionally implemented it this way):
public class StupidDisastrousDatabaseExporter : IDatabaseExporter
{
public ExportedData Export()
{
DoSomethingStupidThatWillDeleteSystemDataAndMakeTheEnterpriseBroke();
...
}
private void DoSomethingStupidThatWillDeleteSystemDataAndMakeTheEnterpriseBroke()
{
//do it
...
}
}
Now, the BackupMaker will never know that it is consuming a stupid and disastrous database exporter, only the composition root does. We can never blame the programmer that wrote the BackupMaker class for this disastrous mistake (or the programmer who designed the IDatabaseExporter contract). But the programmer(s) that are composing the application in the composition root are blamed if they inject a StupidDisastrousDatabaseExporter instance into the constructor of BackupMaker.
Of course, no one should have written the StupidDisastrousDatabaseExporter class in the first place, but I gave you an extreme example to show you that a contract (interface) can never (and should never) guarantee every aspect about its implementors. It should just say enough.
Is there a way to express IDatabaseExporter in such a way that guarantees that implementors of such interface will not make stupid or disastrous actions? No.
Please note that while the BackupMaker is dealing with contracts (no 100% guarantees), the composition root is actually dealing with concrete implementation classes. This gives it the great power (and thus the great responsibility) to guarantee the composition of the correct object graph.
how do I make sure that I'm composing in a sensible way?
You should create automated end-to-end tests for the object graph created by the composition root. Here you are making sure that the composition root has done its big responsibility of composing the objects in a correct way. Here you can test the exact details that you wanted (like that the backup result was in some exact format/details).
Take a look at this article for an approach to automated testing using the Composition Root.
I believe this may be a problem that occurs when focusing too much on object models, at the exclusion of function compositions. Consider the first step in a naive function decomposition (function as in f : a -> b):
exporter: data -> (format, memory), or exception
compressor: memory -> memory, or exception
writer: memory -> side-effect, or exception
backup-maker: (data, exporter, compressor, writer) -> backup-result
So backup-maker, the last function, can be parametized with those three functions, assuming I've considered your use-case correctly, and if the three parameters have the same input and output types, e.g. format, and memory, despite their implementation.
Now, "the guts", or a possible decomposition (read right to left) of backup-maker, with all functions bound, taking data as the argument, and using the composition operator ".":
backup-maker: intermediate-computation . writer . intermediate-computation . compressor . intermediate-computation . exporter
I especially want to note that this model of architecture can be expressed later as either object interfaces, or as first-class functions, e.g. c++ std::function.
Edit: It can also be refined to terms of generics, where memory is a generic type argument, to provide type safety where wanted. E.g.
backup-maker<type M>: (data, exporter<M>, compressor<M>, writer<M>) -> ..
More information about the technique and benefits of Function Decomposition can be found here:
http://jfeltz.com/posts/2015-08-30-cost-decreasing-software-architecture.html
Your requirements seem contradictory:
You want to be specific (allowing only a subset (or only one ?) of combinations)
But you also want to be generic by using interfaces, DI, etc.
My advice is to keep things simple (in your case it means don't try to be generic) until your code evolve.
Only when your code will evolve, refactor in a more generic way. The code below shows a compromise between generic/specific:
public interface ICompressor {
public byte[] compress(byte[] source); //Note: the return type and type argument may not be revelant, just for demonstration purpose
}
public interface IExporter {
public File export(String connectionString); //Note: the return type and type argument may not be revelant, just for demonstration purpose
}
public final class Bzip2 implements ICompressor {
#Override
public final byte[] compress(byte[] source) {
//TODO
}
}
public final class MySQL implements IExporter {
#Override
public final File export(String connnectionString) {
//TODO
}
}
public abstract class ABackupStrategy {
private final ICompressor compressor;
private final IExporter exporter;
public ABackupStrategy(final ICompressor compressor, final IExporter exporter) {
this.compressor = compressor;
this.exporter = exporter;
}
public final void makeBackup() {
//TODO: compose with exporter and compressor to make your backup
}
}
public final class MyFirstBackupStrategy extends ABackupStrategy {
public MyFirstBackupStrategy(final Bzip2 compressor, final MySQL exporter) {
super(compressor, exporter);
}
}
With ICompressor and IExporter, you can easily add other compression algorithm, other database from which to export.
With ABackupStrategy, you can easily define a new allowed combination of concrete compressor/exporter by inheriting it.
Drawback: I had to make ABackupStrategy abstract without declaring any abstract method, which is in contradiction with the OOP-principles.
I have a base class where all common functions are written. I many classes which override this functions by virtual keyword. Like,
public class Base
{
public virtual void sample()
{
..............
}
}
public class a : Base
{
public override sample()
{
}
}
public class implement
{
public void ToSample()
{
Base baseclass = new Base();
Switch(test)
{
case a: baseclass = a();
break;
case b: baseclass = b();
break;
}
baseclass.sample();
}
}
This perfect code for current situation but now I have more class to be assign in switch case. It is not good practice for adding huge amount of cases so I want something that automatically assign child class.
Is anybody know something to be implement ?
As stated in the comment, you can decouple the implementation by using dependency injection. Note however, that in some cases you have no choice but doing that kind of switch (e.g. when you need to create a class based on a text received in a socket). In such cases the important thing is to always keep the switch statement encapsulated in one method and make your objects rely on it (or, in other words, don't copy-and-paste it everywhere :)). The idea here is too keep your system isolated from a potentially harmful code. Of course that if you add a new class you will have to go and modify that method, however you will only have to do it in one time and in one specific place.
Another approach that I have seen (and sometimes used) is to build a mapping between values an classes. So, if your class-creation switch depends on an integer code, you basically create a mapping between codes and classes. What you are doing here is turning a "static" switch into a dynamic behavior, since you can change the mappings contents at any time and thus alter the way your program behaves. A typical implementation would be something like (sorry for the pseudocode, I'm not familiar with C#):
public class implement
{
public void ToSample()
{
class = this.mapping.valueForKey(test);
Base baseclass = new class();
baseclass.sample();
}
}
Note however that for this example to work you need reflection support, which varies according to the language you are using (again, sorry but I don't know the C# specifics).
Finally, you can also check the creational family of patterns for inspiration regarding object creation issues and some well known forms of solving them.
HTH
OOP interfaces.
In my own experience I find interfaces very useful when it comes to design and implement multiple inter-operating modules with multiple developers. For example, if there are two developers, one working on backend and other on frontend (UI) then they can start working in parallel once they have interfaces finalized. Thus, if everyone follows the defined contract then the integration later becomes painless. And thats what interfaces precisely do - define the contract!
Basically it avoids this situation :
Interfaces are very useful when you need a class to operate on generic methods implemented by subclasses.
public class Person
{
public void Eat(IFruit fruit)
{
Console.WriteLine("The {0} is delicious!",fruit.Name);
}
}
public interface IFruit
{
string Name { get; }
}
public class Apple : IFruit
{
public string Name
{
get { return "Apple"; }
}
}
public class Strawberry : IFruit
{
public string Name
{
get { return "Strawberry"; }
}
}
Interfaces are very useful, in case of multiple inheritance.
An Interface totally abstracts away the implementation knowledge from the client.
It allows us to change their behavior dynamically. This means how it will act depends on dynamic specialization (or substitution).
It prevents the client from being broken if the developer made some changes
to implementation or added new specialization/implementation.
It gives an open way to extend an implementation.
Programming language (C#, java )
These languages do not support multiple inheritance from classes, however, they do support multiple inheritance from interfaces; this is yet another advantage of an interface.
Basically Interfaces allow a Program to change the Implementation without having to tell all clients that they now need a "Bar" Object instead of a "Foo" Object. It tells the users of this class what it does, not what it is.
Example:
A Method you wrote wants to loop through the values given to it. Now there are several things you can iterate over, like Lists, Arrays and Collections.
Without Interfaces you would have to write:
public class Foo<T>
{
public void DoSomething(T items[])
{
}
public void DoSomething(List<T> items)
{
}
public void DoSomething(SomeCollectionType<T> items)
{
}
}
And for every new iteratable type you'd have to add another method or the user of your class would have to cast his data. For example with this solution if he has a Collection of FooCollectionType he has to cast it to an Array, List or SomeOtherCollectionType.
With interfaces you only need:
public class Foo<T>
{
public void DoSomething(IEnumerable<T> items)
{
}
}
This means your class only has to know that, whatever the user passes to it can be iterated over. If the user changes his SomeCollectionType to AnotherCollectionType he neither has to cast nor change your class.
Take note that abstract base classes allow for the same sort of abstraction but have some slight differences in usage.
To show an example what is this question about:
I have currently a dilemma in PHP project I'm working on. I have in mind a method that will be used by multiple classes (UIs in this case - MVC model), but I'm not sure how to represent such methods in OO design. The first thing that came into my mind was to create a class with static functions that I'd call whenever I need them. However I'm not sure if it's the right thing to do.
To be more precise, I want to work, for example, with time. So I'll need several methods that handle time. I was thinking about creating a Time class where I'd be functions that check whether the time is in correct format etc.
Some might say that I shouldn't use class for this at all, since in PHP I can still use procedural code. But I'm more interested in answer that would enlighten me how to approach such situations in OOP / OOD.
So the actual questions are: How to represent such methods? Is static function approach good enough or should I reconsider anything else?
I would recommend creating a normal class the contains this behavior, and then let that class implement an interface extracted from the class' members.
Whenever you need to call those methods, you inject the interface (not the concrete class) into the consumer. This lets you vary the two independently of each other.
This may sound like more work, but is simply the Strategy design pattern applied.
This will also make it much easier to unit test the code, because the code is more loosely coupled.
Here's an example in C#.
Interface:
public interface ITimeMachine
{
IStopwatch CreateStopwatch();
DateTimeOffset GetNow();
}
Production implementation:
public class RealTimeMachine : ITimeMachine
{
#region ITimeMachine Members
public IStopwatch CreateStopwatch()
{
return new StopwatchAdapter();
}
public DateTimeOffset GetNow()
{
return DateTimeOffset.Now;
}
#endregion
}
and here's a consumer of the interface:
public abstract class PerformanceRecordingSession : IDisposable
{
private readonly IStopwatch watch;
protected PerformanceRecordingSession(ITimeMachine timeMachine)
{
if (timeMachine == null)
{
throw new ArgumentNullException("timeMachine");
}
this.watch = timeMachine.CreateStopwatch();
this.watch.Start();
}
public abstract void Record(long elapsedTicks);
public virtual void StopRecording()
{
this.watch.Stop();
this.Record(this.watch.ElapsedTicks);
}
}
Although you say you want a structure for arbitrary, unrelated functions, you have given an example of a Time class, which has many related functions. So from an OO point of view you would create a Time class and have a static function getCurrentTime(), for example, which returns an instance of this class. Or you could define that the constuctors default behaviour is to return the current time, whichever you like more. Or both.
class DateTime {
public static function getNow() {
return new self();
}
public function __construct() {
$this->setDateTime('now');
}
public function setDateTime($value) {
#...
}
}
But apart from that, there is already a builtin DateTime class in PHP.
Use a class as a namespace. So yes, have a static class.
class Time {
public static function getCurrentTime() {
return time() + 42;
}
}
I don't do PHP, but from an OO point of view, placing these sorts of utility methods as static methods is fine. If they are completely reusable in nature, consider placing them in a utils class.