https://en.wikipedia.org/wiki/Decorator_pattern
The decorator pattern is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.
The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern.
http://javapapers.com/design-patterns/decorator-pattern/
To extend or modify the behaviour of ‘an instance’ at runtime decorator design pattern is used. Inheritance is used to extend the abilities of ‘a class’. Unlike inheritance, you can choose any single object of a class and modify its behaviour leaving the other instances unmodified.
In implementing the decorator pattern you construct a wrapper around an object by extending its behavior. The wrapper will do its job before or after and delegate the call to the wrapped instance.
Intent
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
Client-specified embellishment of a core object by recursively wrapping it.
http://www.oodesign.com/decorator-pattern.html
· Decorator design pattern is used to enhance the functionality of a particular object at run-time or dynamically.
· At the same time other instance of same class will not be affected by this so individual object gets the new behavior.
Check list
· When sub classing is become impractical and we need large number of different possibilities to make independent object or we can say we have number of combination for an object.
· Secondly when we want to add functionality to individual object not to all object at run-time we use decorator design pattern.
Example
http://java67.blogspot.com/2013/07/decorator-design-pattern-in-java-real-life-example-tutorial.html
Sandwich,WhiteBreadSandWich
https://sourcemaking.com/design_patterns/decorator/java/3
https://en.wikipedia.org/wiki/Decorator_pattern
Usage in JDK
-java.io.BufferedInputStream(InputStream)
-java.io.DataInputStream(InputStream)
-java.io.BufferedOutputStream(OutputStream)
-java.util.zip.ZipOutputStream(OutputStream)
-java.util.Collections.unmodifiableCollection|synchronizedCollection
Collections.checkedCollection
Returns a dynamically typesafe view of the specified collection. Any attempt to insert an element of the wrong type will result in an immediate ClassCastException.
#checked[List|Map|Set|SortedSet|SortedMap]()
http://www.programcreek.com/2012/05/java-design-pattern-decorator-decorate-your-girlfriend/
InputStreamReader(InputStream in) - bridge from byte streams to character streams. InputSteamReader reads bytes and translates them into characters using the specified character encoding. ==> adapter pattern
BufferedReader(Reader in) - read text from a character stream and buffer characters in order to provide efficient reading methods(e.g., readLine())
Advantage of Decorator design Pattern in Java
1. Decorator Pattern is flexible than inheritance because inheritance add responsibilities at compile time and it will add at run-time.
2. Decorator pattern enhance or modify the object functionality
Disadvantage
Main disadvantage of using Decorator Pattern in Java is that the code maintenance can be a problem as it provides a lot of similar kind of small objects (each decorator).
JDK8
http://www.javacodegeeks.com/2015/12/decorator-design-pattern-using-lambdas.html
Java IO : 流,以及装饰器模式在其上的运用
The decorator pattern is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.
The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern.
http://javapapers.com/design-patterns/decorator-pattern/
To extend or modify the behaviour of ‘an instance’ at runtime decorator design pattern is used. Inheritance is used to extend the abilities of ‘a class’. Unlike inheritance, you can choose any single object of a class and modify its behaviour leaving the other instances unmodified.
In implementing the decorator pattern you construct a wrapper around an object by extending its behavior. The wrapper will do its job before or after and delegate the call to the wrapped instance.
Intent
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
Client-specified embellishment of a core object by recursively wrapping it.
http://www.oodesign.com/decorator-pattern.html
- Component - Interface for objects that can have responsibilities added to them dynamically.
- ConcreteComponent - Defines an object to which additional responsibilities can be added.
- Decorator - Maintains a reference to a Component object and defines an interface that conforms to Component's interface.
- Concrete Decorators - Concrete Decorators extend the functionality of the component by adding state or adding behavior
· Decorator design pattern is used to enhance the functionality of a particular object at run-time or dynamically.
· At the same time other instance of same class will not be affected by this so individual object gets the new behavior.
Check list
- Ensure the context is: a single core (or non-optional) component, several optional embellishments or wrappers, and an interface that is common to all.
- Create a "Lowest Common Denominator" interface that makes all classes interchangeable.
- Create a second level base class (Decorator) to support the optional wrapper classes.
- The Core class and Decorator class inherit from the LCD interface.
- The Decorator class declares a composition relationship to the LCD interface, and this data member is initialized in its constructor.
- The Decorator class delegates to the LCD object.
- Define a Decorator derived class for each optional embellishment.
- Decorator derived classes implement their wrapper functionality - and - delegate to the Decorator base class.
- The client configures the type and ordering of Core and Decorator objects.
· When sub classing is become impractical and we need large number of different possibilities to make independent object or we can say we have number of combination for an object.
· Secondly when we want to add functionality to individual object not to all object at run-time we use decorator design pattern.
The decorator pattern is an alternative to subclassing. Subclassing adds behavior at compile time, and the change affects all instances of the original class; decorating can provide new behavior at run-time for individual objects.
This difference becomes most important when there are several independent ways of extending functionality. In some object-oriented programming languages, classes cannot be created at runtime, and it is typically not possible to predict, at design time, what combinations of extensions will be needed. This would mean that a new class would have to be made for every possible combination. By contrast, decorators are objects, created at runtime, and can be combined on a per-use basis.
Example
http://java67.blogspot.com/2013/07/decorator-design-pattern-in-java-real-life-example-tutorial.html
Sandwich,WhiteBreadSandWich
SandWichDecorator
public abstract class SandWichDecorator extends Sandwich
public class CheeseDecorator extends SandWichDecorator{
public abstract class Sandwich { protected String description = "Sandwich"; public String getDescription(){ return description; } public abstract BigDecimal price(); }
https://en.wikipedia.org/wiki/Decorator_pattern
coffee making scenario
// The abstract Coffee class defines the functionality of Coffee implemented by decorator public abstract class Coffee { public abstract double getCost(); // Returns the cost of the coffee public abstract String getIngredients(); // Returns the ingredients of the coffee } // Extension of a simple coffee without any extra ingredients public class SimpleCoffee extends Coffee { public double getCost() { return 1; } public String getIngredients() { return "Coffee"; } }
// Abstract decorator class - note that it extends Coffee abstract class public abstract class CoffeeDecorator extends Coffee { protected final Coffee decoratedCoffee; public CoffeeDecorator(Coffee c) { this.decoratedCoffee = c; } public double getCost() { // Implementing methods of the abstract class return decoratedCoffee.getCost(); } public String getIngredients() { return decoratedCoffee.getIngredients(); } } // Decorator WithMilk mixes milk into coffee. // Note it extends CoffeeDecorator. class WithMilk extends CoffeeDecorator { public WithMilk(Coffee c) { super(c); } public double getCost() { // Overriding methods defined in the abstract superclass return super.getCost() + 0.5; } public String getIngredients() { return super.getIngredients() + ", Milk"; } } // Decorator WithSprinkles mixes sprinkles onto coffee. // Note it extends CoffeeDecorator. class WithSprinkles extends CoffeeDecorator {}
Usage in JDK
-java.io.BufferedInputStream(InputStream)
-java.io.DataInputStream(InputStream)
-java.io.BufferedOutputStream(OutputStream)
-java.util.zip.ZipOutputStream(OutputStream)
-java.util.Collections.unmodifiableCollection|synchronizedCollection
Collections.checkedCollection
Returns a dynamically typesafe view of the specified collection. Any attempt to insert an element of the wrong type will result in an immediate ClassCastException.
#checked[List|Map|Set|SortedSet|SortedMap]()
http://www.programcreek.com/2012/05/java-design-pattern-decorator-decorate-your-girlfriend/
1. Decorator Pattern is flexible than inheritance because inheritance add responsibilities at compile time and it will add at run-time.
2. Decorator pattern enhance or modify the object functionality
Disadvantage
Main disadvantage of using Decorator Pattern in Java is that the code maintenance can be a problem as it provides a lot of similar kind of small objects (each decorator).
JDK8
http://www.javacodegeeks.com/2015/12/decorator-design-pattern-using-lambdas.html
Java IO : 流,以及装饰器模式在其上的运用
在输出流OutputStream中,如果你需要向一个输出流写入数据,可以调用
如果你希望你向流中写入的数据能够尽快地输送到目的地,比如说文件,那么可以在写入数据后,调用
使用完流后应该调用其
void write(int b)
方法,这个方法会将b的低八位写入流中,高24位将会被自动忽略。如果想要批量写入数据呢,那么可以调用void write(byte[] b)
方法将一个字节数组的内容全部写入流中,同时还有void write(byte[] b, int off, int len)
可以让你指定从哪里写入多少数据。如果你希望你向流中写入的数据能够尽快地输送到目的地,比如说文件,那么可以在写入数据后,调用
flush()
方法将当前输出流刷到操作系统层面的缓冲区中。不过需要注意的是,此方法并不保证数据立马就能刷到实际的物理目的地(比如说存储)。使用完流后应该调用其
close()
方法将流关闭,流关闭时,将会先flush,后关闭。
java.io.ByteArrayOutputStream.write(int)
public synchronized void write(int b) {
ensureCapacity(count + 1);
buf[count] = (byte) b;
count += 1;
}
在输入流InputStream中,可以通过
int read()
方法来从流中读取一个字节,批量读取字节可以通过int read(byte[] b)
或者int read(byte[] b, int off, int len)
来实现,这两个方法的返回值为实际读取到的字节数。如果需要重复读取流中某段数据,可以在读取之前先使用void mark(int readlimit)
方法在当前位置做一个记号,之后通过void reset()
方法返回到之前做标记的位置,不过在做这些标记操作之前,需要先通过boolean markSupported()
方法来确定该流是否支持标记。如果对某些可预知的数据不感兴趣,可以使用long skip(long n)
来调过一些流中的一些数据。
使用完流,无论是输入还是输出流,都要调用其
close()
方法对其进行关闭。
InputStream这个抽象类有一个子类与上述其它子类非常不同,这个子类就是FilterInputStream,可参见上图中的InputStream族谱图。
翻开FilterInputStream的代码,我们可以看到,它内部又维护了一个InputStream的成员对象,并且它的所有方法,都是调用这个成员对象的同名方法。
换句话说,FilterInputStream它什么事都不做。就是把调用委托给内部的InputStream成员对象。
换句话说,FilterInputStream它什么事都不做。就是把调用委托给内部的InputStream成员对象。
FilterInputStream的又有其子类,分别是:
- BufferedInputStream
- DataInputStream
- LineNumberInputStream
- PushbackInputStream
虽然从上面代码看FilterInputStream并没有做什么有卵用的事,但是它的子类可不同了,以BufferedInputStream为例,这个类提供了提前读取数据的功能,也就是缓冲的功能。可以看看它的read方法:
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
}
可以看到,当pos>=count时,意即需要提前缓冲一些数据的时候到了,那么就会调用fill()将缓冲区加满,以便后续读取。由于本文只讨论io流的装饰器模式,
比如我们常用的FileInputStream,它并没有缓冲功能,我们每次调用read,都会向操作系统发起调用索要数据。假如我们通过BufferedInputStream来装饰它,那么每次调用read,会预先向操作系统多拿一些数据,这样就不知不觉中提高了程序的性能。如以下代码所示:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("/home/user/abc.txt")));
同理,对于其它的FilterInputStream的子类,其作用也是一样的,那就是装饰一个InputStream,为它添加它原本不具有的功能。OutputStream以及家属对于装饰器模式的体现,也以此类推。
BufferedOutputStream
public synchronized void write(int b) throws IOException {
if (count >= buf.length) {
flushBuffer();
}
buf[count++] = (byte)b;
}
public synchronized void write(byte b[], int off, int len) throws IOException {
if (len >= buf.length) {
/* If the request length exceeds the size of the output buffer,
flush the output buffer and then write the data directly.
In this way buffered streams will cascade harmlessly. */
flushBuffer();
out.write(b, off, len);
return;
}
if (len > buf.length - count) {
flushBuffer();
}
System.arraycopy(b, off, buf, count, len);
count += len;
}
/** Flush the internal buffer */
private void flushBuffer() throws IOException {
if (count > 0) {
out.write(buf, 0, count);
count = 0;
}
}
BufferedInputStream
* The internal buffer array where the data is stored. When necessary,
* it may be replaced by another array of
* a different size.
*/
protected volatile byte buf[];
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
}
* Fills the buffer with more data, taking into account
* shuffling and other tricks for dealing with marks.
* Assumes that it is being called by a synchronized method.
* This method also assumes that all data has already been read in,
* hence pos > count.
*/
private void fill() throws IOException {
byte[] buffer = getBufIfOpen();
if (markpos < 0)
pos = 0; /* no mark: throw away the buffer */
else if (pos >= buffer.length) /* no room left in buffer */
if (markpos > 0) { /* can throw away early part of the buffer */
int sz = pos - markpos;
System.arraycopy(buffer, markpos, buffer, 0, sz);
pos = sz;
markpos = 0;
} else if (buffer.length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
} else if (buffer.length >= MAX_BUFFER_SIZE) {
throw new OutOfMemoryError("Required array size too large");
} else { /* grow buffer */
int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
pos * 2 : MAX_BUFFER_SIZE;
if (nsz > marklimit)
nsz = marklimit;
byte nbuf[] = new byte[nsz];
System.arraycopy(buffer, 0, nbuf, 0, pos);
if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
// Can't replace buf if there was an async close.
// Note: This would need to be changed if fill()
// is ever made accessible to multiple threads.
// But for now, the only way CAS can fail is via close.
// assert buf == null;
throw new IOException("Stream closed");
}
buffer = nbuf;
}
count = pos;
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
count = n + pos;
}
private byte[] getBufIfOpen() throws IOException {
byte[] buffer = buf;
if (buffer == null)
throw new IOException("Stream closed");
return buffer;
}
* Atomic updater to provide compareAndSet for buf. This is
* necessary because closes can be asynchronous. We use nullness
* of buf[] as primary indicator that this stream is closed. (The
* "in" field is also nulled out on close.)
*/
private static final
AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
AtomicReferenceFieldUpdater.newUpdater
(BufferedInputStream.class, byte[].class, "buf");
public void close() throws IOException {
byte[] buffer;
while ( (buffer = buf) != null) {
if (bufUpdater.compareAndSet(this, buffer, null)) {
InputStream input = in;
in = null;
if (input != null)
input.close();
return;
}
// Else retry in case a new buf was CASed in fill()
}
}