Go on!争取一天写2-3个模式。
装饰者模式,顾名思义,肯定有去装饰和被装饰两种类。
好,这里我举一个Head First上的例子,就是我们喝咖啡,咖啡是个类,但是我们现在需要给咖啡添加一些东西,比如说添糖,添调料,呢我们应该怎么办,不停的创建对象利用set方法,很明显是不好的,也不符合开闭原则。这个时候就显示出装饰者模式的优点了,我只需要创建装饰对象,并不断装饰被装饰者即可。
Java中我们常见的Io类就是用的装饰者模式。
package com.modedesign.decker; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; /** * @author ctt: * @version 创建时间:2016年5月10日 下午8:58:33 类说明 */ public class InputTest { public static void main(String[] args) throws Exception { int c = 0; FileOutputStream fileOutputStream = new FileOutputStream("test.txt"); fileOutputStream.write(new String("heihei").getBytes()); InputStream inputStream = new LowerCaseInputStreame( new BufferedInputStream(new FileInputStream("test.txt"))); while ((c = inputStream.read()) >= 0) { System.out.println((char) c); } inputStream.close(); fileOutputStream.close(); } }
package com.modedesign.decker; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; /** * @author ctt: * @version 创建时间:2016年5月10日 下午8:46:26 * 类说明 */ public class LowerCaseInputStreame extends FilterInputStream{ protected LowerCaseInputStreame(InputStream in) { super(in); } @Override public int read() throws IOException { int a = super.read(); return a == -1 ? a : Character.toLowerCase((char)a); } @Override public int read(byte[] b, int off, int len) throws IOException { int result = super.read(b, off, len); for (int i = off; i < off + result; i++) { b[i] = (byte) Character.toLowerCase((char)b[i]); } return result; } }
/* * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package java.io; /** * A <code>FilterInputStream</code> contains * some other input stream, which it uses as * its basic source of data, possibly transforming * the data along the way or providing additional * functionality. The class <code>FilterInputStream</code> * itself simply overrides all methods of * <code>InputStream</code> with versions that * pass all requests to the contained input * stream. Subclasses of <code>FilterInputStream</code> * may further override some of these methods * and may also provide additional methods * and fields. * * @author Jonathan Payne * @since JDK1.0 */ public class FilterInputStream extends InputStream { /** * The input stream to be filtered. */ protected volatile InputStream in; /** * Creates a <code>FilterInputStream</code> * by assigning the argument <code>in</code> * to the field <code>this.in</code> so as * to remember it for later use. * * @param in the underlying input stream, or <code>null</code> if * this instance is to be created without an underlying stream. */ protected FilterInputStream(InputStream in) { this.in = in; } /** * Reads the next byte of data from this input stream. The value * byte is returned as an <code>int</code> in the range * <code>0</code> to <code>255</code>. If no byte is available * because the end of the stream has been reached, the value * <code>-1</code> is returned. This method blocks until input data * is available, the end of the stream is detected, or an exception * is thrown. * <p> * This method * simply performs <code>in.read()</code> and returns the result. * * @return the next byte of data, or <code>-1</code> if the end of the * stream is reached. * @exception IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ public int read() throws IOException { return in.read(); } /** * Reads up to <code>byte.length</code> bytes of data from this * input stream into an array of bytes. This method blocks until some * input is available. * <p> * This method simply performs the call * <code>read(b, 0, b.length)</code> and returns * the result. It is important that it does * <i>not</i> do <code>in.read(b)</code> instead; * certain subclasses of <code>FilterInputStream</code> * depend on the implementation strategy actually * used. * * @param b the buffer into which the data is read. * @return the total number of bytes read into the buffer, or * <code>-1</code> if there is no more data because the end of * the stream has been reached. * @exception IOException if an I/O error occurs. * @see java.io.FilterInputStream#read(byte[], int, int) */ public int read(byte b[]) throws IOException { return read(b, 0, b.length); } /** * Reads up to <code>len</code> bytes of data from this input stream * into an array of bytes. If <code>len</code> is not zero, the method * blocks until some input is available; otherwise, no * bytes are read and <code>0</code> is returned. * <p> * This method simply performs <code>in.read(b, off, len)</code> * and returns the result. * * @param b the buffer into which the data is read. * @param off the start offset in the destination array <code>b</code> * @param len the maximum number of bytes read. * @return the total number of bytes read into the buffer, or * <code>-1</code> if there is no more data because the end of * the stream has been reached. * @exception NullPointerException If <code>b</code> is <code>null</code>. * @exception IndexOutOfBoundsException If <code>off</code> is negative, * <code>len</code> is negative, or <code>len</code> is greater than * <code>b.length - off</code> * @exception IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ public int read(byte b[], int off, int len) throws IOException { return in.read(b, off, len); } /** * Skips over and discards <code>n</code> bytes of data from the * input stream. The <code>skip</code> method may, for a variety of * reasons, end up skipping over some smaller number of bytes, * possibly <code>0</code>. The actual number of bytes skipped is * returned. * <p> * This method simply performs <code>in.skip(n)</code>. * * @param n the number of bytes to be skipped. * @return the actual number of bytes skipped. * @exception IOException if the stream does not support seek, * or if some other I/O error occurs. */ public long skip(long n) throws IOException { return in.skip(n); } /** * Returns an estimate of the number of bytes that can be read (or * skipped over) from this input stream without blocking by the next * caller of a method for this input stream. The next caller might be * the same thread or another thread. A single read or skip of this * many bytes will not block, but may read or skip fewer bytes. * <p> * This method returns the result of {@link #in in}.available(). * * @return an estimate of the number of bytes that can be read (or skipped * over) from this input stream without blocking. * @exception IOException if an I/O error occurs. */ public int available() throws IOException { return in.available(); } /** * Closes this input stream and releases any system resources * associated with the stream. * This * method simply performs <code>in.close()</code>. * * @exception IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ public void close() throws IOException { in.close(); } /** * Marks the current position in this input stream. A subsequent * call to the <code>reset</code> method repositions this stream at * the last marked position so that subsequent reads re-read the same bytes. * <p> * The <code>readlimit</code> argument tells this input stream to * allow that many bytes to be read before the mark position gets * invalidated. * <p> * This method simply performs <code>in.mark(readlimit)</code>. * * @param readlimit the maximum limit of bytes that can be read before * the mark position becomes invalid. * @see java.io.FilterInputStream#in * @see java.io.FilterInputStream#reset() */ public synchronized void mark(int readlimit) { in.mark(readlimit); } /** * Repositions this stream to the position at the time the * <code>mark</code> method was last called on this input stream. * <p> * This method * simply performs <code>in.reset()</code>. * <p> * Stream marks are intended to be used in * situations where you need to read ahead a little to see what's in * the stream. Often this is most easily done by invoking some * general parser. If the stream is of the type handled by the * parse, it just chugs along happily. If the stream is not of * that type, the parser should toss an exception when it fails. * If this happens within readlimit bytes, it allows the outer * code to reset the stream and try another parser. * * @exception IOException if the stream has not been marked or if the * mark has been invalidated. * @see java.io.FilterInputStream#in * @see java.io.FilterInputStream#mark(int) */ public synchronized void reset() throws IOException { in.reset(); } /** * Tests if this input stream supports the <code>mark</code> * and <code>reset</code> methods. * This method * simply performs <code>in.markSupported()</code>. * * @return <code>true</code> if this stream type supports the * <code>mark</code> and <code>reset</code> method; * <code>false</code> otherwise. * @see java.io.FilterInputStream#in * @see java.io.InputStream#mark(int) * @see java.io.InputStream#reset() */ public boolean markSupported() { return in.markSupported(); } }