Wednesday, May 8, 2013

Design Principles


  • Encapsulation is breaking your application into logical parts that have a clear boundary that allows an object to hide its data and methods from other objects.
  • Encapsulate what varies.
Information hiding (encapsulation) is important for many reasons, most of which stem from the fact that it decouples the modules that comprise a system, allowing them to be developed, tested, optimized, used, understood, and modified in isolation. This speeds up system development because modules can be developed in parallel. It eases the burden of maintenance because modules can be understood more quickly and debugged with little fear of harming other modules.

The rule of thumb is simple: make each class or member as inaccessible as possible.
  • Code to an interface rather than to an implementation (software is easier to extend).
  • Classes are about behaviour and functionality.
  • Open-Closed Principle (OCP) - classes should be open for extension (new functionality), and closed for modification. (keeps your software reusable, but still flexible) If you want to add new functionality you should extend the entity.
    • open for extension: new behaviour can be added to satisfy the new requirements 
    • close for modification: to extending the new behaviour are not required modify the existing code
  • Don't Repeat Yourself (DRY) - avoid duplicate code by abstracting out things that are common and placing those things in a single location. (DRY is about having each piece of information and behavior in your system in a single, sensible place)
  • Single Responsibility Principle (SRP) - every object in your system should have a single responsibility, and all the object's services should be focused on carrying out that single responsibility. 
    • Each class in your application should have only one reason to change. 
    • Cohesion is another name for SRP. 
    • High cohesion is the desirable state of a class whose members support a single, well-focused role or responsibility.
  • Liskov Substitution Principle (LSP) - subtypes must be substitutable for their base types. (ensures that you use inheritance correctly)
  • Delegation is when you hand over the responsibility for a particular task to another class or method. (If you need to use functionality in another class, but you don't want to change that functionality, consider using delegation instead of inheritance.)
  • Composition lets you choose a behavior from a family of behaviors, often via several implementations of an interface. (the composing object owns the behaviors it uses, and they stop existing as soon as the composing object does)
  • Aggregation is when one class is used as part of another class, but still exists outside of that other class.
  • Dependency inversion principle (DIP)
    • High level modules should not depend upon low-level modules. Both should depend upon abstractions.
    • Abstractions should never depend upon details. Details should depend upon abstractions.
Unlike method invocation, inheritance violates encapsulation. In other words, a subclass depends on the implementation details of its superclass for its proper function. The superclass’s implementation may change from release to release, and if it does, the subclass may break, even though its code has not been touched. As a consequence, a subclass must evolve in tandem with its superclass, unless the superclass’s authors have designed and documented it specifically for the purpose of being extended.
Instead of extending an existing class, give your new class a private field that references an instance of the existing class. This design is called composition because the existing class becomes a component of the new one. Each instance method in the new class invokes the corresponding method on the contained instance of the existing class and returns the results. This is known as forwarding, and the methods in the new class are known as forwarding methods. The resulting class will be rock solid, with no dependencies on the implementation details of the existing class. Even adding new methods to the existing class will have no impact on the new class. 

The features in your system are what the system does (they reflect system's functionality).
Use cases show how the system is used. 
Features and use cases work together, but features are not always reflected in your use cases.

SOLID (single responsibility, open-closed, Liskov substitution, interface segregation and dependency inversion) is a mnemonic acronym introduced by Michael Feathers for the "first five principles" named by Robert C. Martin in the early 2000s that stands for five basic principles of object-oriented programming and design.


Ref: 


Head-First-Object-Oriented-Analysis-Design
Effective Java
10 Object Oriented Design Principles Java Programmer should know
YAGNI - Martin Fowler
Core Design Principles for Software Developers by Venkat Subramaniam
SOLID Principles : The Definitive Guide
The Principles of OOD (UncleBob)

Monday, May 6, 2013

Disk Helper


Utility class for saving, opening and zipping files.

public class DiskHelper
{

/**
* saveToDisk i openFile
*/
public static void printFileObject(FileObject fo)
{
File file = saveToDisk(fo, fo.getFilename());
openFile(file);
}

public static File saveToDisk(FileObject fo, String fileName)
{
String pdfSuffix = "";
if (!fileName.contains(".pdf"))
{
pdfSuffix = ".pdf";
}

File file = new File("c://tmp//" + fileName + pdfSuffix);

int i = 0;
while (file.exists())
{
i++;
file = new File("c://tmp//" + fileName.replace(".pdf", "") + "_" + i + ".pdf");
}

System.out.println("file.exists: " + file.exists());

OutputStream os;
try
{
os = new FileOutputStream(file);
os.write(fo.getContent());
os.flush();
os.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
return file;

}

public static void openFile(File file)
{
StringBuilder sb = new StringBuilder();
sb.append("cmd.exe /C start ");
sb.append(file.getAbsolutePath());
System.out.println("openFile: " + sb);
try
{
Runtime.getRuntime().exec(sb.toString());
}
catch (IOException e)
{
e.printStackTrace();
}
}

private static int byteValue = 1024;

/**
* http://www.mkyong.com/java/how-to-compress-files-in-zip-format/
*/
public static void zipFile(String fileName, File... files)
{
byte[] buffer = new byte[1024];

try
{
File zipfile = new File("C:\\tmp\\" + fileName + ".zip");
FileOutputStream fos = new FileOutputStream(zipfile);
ZipOutputStream zos = new ZipOutputStream(fos);

for (File file : files)
{
System.out.println("file.getName(): " + file.getName() + ", file.length(): " + file.length() / byteValue + " KB");
ZipEntry ze = new ZipEntry(file.getName());
zos.putNextEntry(ze);
FileInputStream in = new FileInputStream(file.getAbsoluteFile());
System.out.println("file.getAbsoluteFile(): " + file.getAbsoluteFile());

int len;
while ((len = in.read(buffer)) > 0)
{
zos.write(buffer, 0, len);
}

in.close();
}

System.out.println("zipfile.getName(): " + zipfile.getName() + ", zipfile.length(): " + zipfile.length() / byteValue + " KB");

zos.closeEntry();
zos.close();

System.out.println("Done");

}
catch (IOException ex)
{
ex.printStackTrace();
}
}

public static void deleteFiles(File... files)
{
for (File file : files)
{
file.delete();
}
}

}



public class FileObject
{
private String filename;
private byte[] content;

public byte[] getContent()
{
return content;
}

public void setContent(byte[] content)
{
this.content = content;
}

public String getFilename()
{
return filename;
}

public void setFilename(String filename)
{
this.filename = filename;
}

}