`
hudepin
  • 浏览: 42907 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

适配器模式(Adapter)

阅读更多
适配器模式(Adapter)

还是先从引入说起,先来看一个问题吧,总所周知,在中国通用的电压时 220V,

而美国电压则是 110V,如果有经常在美国和中国之间跑的 IT 人,而其笔记本都是随身携带的,

那么它的笔记本的电压问题如何解决呢?

(因为在美国和中国电压不同,所以一般的电器会不通用的)

而适配器在这个问题上体现得妙极妙极。

现在的笔记本都有一个电源适配器,而正是这个电源适配器来解决上面提到的适配器问题,

比如,一款索尼笔记本,其输入电流为交流100V~240V,而输出则是统一的直流 19.5V,

在电源适配器的一端输入交流电流,然后通过电源适配器把电源变成需要的电压,

也就是适配器的作用是使得一个东西适合另外一个东西。

            

             

下面来给出适配器模式的定义

适配器模式将一个接口转换成另外一个接口,以符合客户的期望。

主要用于以下情况:

比如现在我有一个旧的软件系统,而其中有一个组件呢,它已经过时了,需要更新,

所以我又有了第三方的组件(新组件),但是旧组件的接口和新组件的接口不同,

同时,您又不想去改变现有的代码(如果系统大的话,或许您改都改不了),

此时呢,就是让适配器模式登场的时刻了,

您可以通过适配器模式将新组件的一些接口转换成为你所期望的接口(也就是和新组件符合),

这样的话,您就无需要改变原来的代码而轻松实现从旧组件更新到新组件了。

然后呢,还有一种比较好的应用就是,比如现在很多在 Windows 上的东西都不能在 Linux 上运行,

比如一个 WINE 的工具,它呢,就允许用户在 Linux 环境下运行 Windows 程序,这也是一种适配器。


适配器模式的应用
 适配器模式是Java I/O库中第二个最为重要的设计模式。
 InputStream原始流处理器中的适配器模式
 InputStream类型的原始流处理器是适配器模式的应用。
 ByteArrayInputStream是一个适配器类
 ByteArrayInputStream继承了InputStream的接口,而封装了一个byte数组。换言之,它将一个byte数组的接口适配成InputStream流处理器的接口。
 我们知道Java语言支持四种类型:Java接口,Java类,Java数组,原始类型(即int,float等)。前三种是引用类型,类和数组的实例是对象,原始类型的值不是对象。
也即,Java语言的数组是像所有的其他对象一样的对象,而不管数组中所存储的元素类型是什么。
这样一来的话,ByteArrayInputStream就符合适配器模式的描述,是一个对象形式的适配器类。
FileInputStream是一个适配器类
  在FileInputStream继承了InputStrem类型,同时持有一个对FileDiscriptor的引用。这是将一个FileDiscriptor对象适配成InputStrem类型的对象形式的适配器模式

其实呢,可以这样来理解适配器模式的,适配器模式就是将一些对象包装起来,

然后让它们的接口看起来是别的接口。
/*
 * %W% %E%
 *
 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.io;

import java.nio.channels.FileChannel;
import sun.nio.ch.FileChannelImpl;


/**
 * A <code>FileInputStream</code> obtains input bytes
 * from a file in a file system. What files
 * are  available depends on the host environment.
 *
 * <p><code>FileInputStream</code> is meant for reading streams of raw bytes
 * such as image data. For reading streams of characters, consider using
 * <code>FileReader</code>.
 *
 * @author  Arthur van Hoff
 * @version %I%, %G%
 * @see     java.io.File
 * @see     java.io.FileDescriptor
 * @see	    java.io.FileOutputStream
 * @since   JDK1.0
 */
public
class FileInputStream extends InputStream
{
    /* File Descriptor - handle to the open file */
    private FileDescriptor fd;

    private FileChannel channel = null;

    private Object closeLock = new Object();
    private volatile boolean closed = false;

    private static final ThreadLocal<Boolean> runningFinalize =
        new ThreadLocal<Boolean>();

    private static boolean isRunningFinalize() {
        Boolean val;
        if ((val = runningFinalize.get()) != null)
            return val.booleanValue();
        return false;
    }

    /**
     * Creates a <code>FileInputStream</code> by
     * opening a connection to an actual file,
     * the file named by the path name <code>name</code>
     * in the file system.  A new <code>FileDescriptor</code>
     * object is created to represent this file
     * connection.
     * <p>
     * First, if there is a security
     * manager, its <code>checkRead</code> method
     * is called with the <code>name</code> argument
     * as its argument.
     * <p>
     * If the named file does not exist, is a directory rather than a regular
     * file, or for some other reason cannot be opened for reading then a
     * <code>FileNotFoundException</code> is thrown.
     *
     * @param      name   the system-dependent file name.
     * @exception  FileNotFoundException  if the file does not exist,
     *                   is a directory rather than a regular file,
     *                   or for some other reason cannot be opened for
     *                   reading.
     * @exception  SecurityException      if a security manager exists and its
     *               <code>checkRead</code> method denies read access
     *               to the file.
     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
     */
    public FileInputStream(String name) throws FileNotFoundException {
        this(name != null ? new File(name) : null);
    }

    /**
     * Creates a <code>FileInputStream</code> by
     * opening a connection to an actual file,
     * the file named by the <code>File</code>
     * object <code>file</code> in the file system.
     * A new <code>FileDescriptor</code> object
     * is created to represent this file connection.
     * <p>
     * First, if there is a security manager,
     * its <code>checkRead</code> method  is called
     * with the path represented by the <code>file</code>
     * argument as its argument.
     * <p>
     * If the named file does not exist, is a directory rather than a regular
     * file, or for some other reason cannot be opened for reading then a
     * <code>FileNotFoundException</code> is thrown.
     *
     * @param      file   the file to be opened for reading.
     * @exception  FileNotFoundException  if the file does not exist,
     *                   is a directory rather than a regular file,
     *                   or for some other reason cannot be opened for
     *                   reading.
     * @exception  SecurityException      if a security manager exists and its
     *               <code>checkRead</code> method denies read access to the file.
     * @see        java.io.File#getPath()
     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
     */
    public FileInputStream(File file) throws FileNotFoundException {
	String name = (file != null ? file.getPath() : null);
	SecurityManager security = System.getSecurityManager();
	if (security != null) {
	    security.checkRead(name);
	}
        if (name == null) {
            throw new NullPointerException();
        }
	fd = new FileDescriptor();
        fd.incrementAndGetUseCount();
	open(name);
    }

    /**
     * Creates a <code>FileInputStream</code> by using the file descriptor
     * <code>fdObj</code>, which represents an existing connection to an
     * actual file in the file system.
     * <p>
     * If there is a security manager, its <code>checkRead</code> method is
     * called with the file descriptor <code>fdObj</code> as its argument to
     * see if it's ok to read the file descriptor. If read access is denied
     * to the file descriptor a <code>SecurityException</code> is thrown.
     * <p>
     * If <code>fdObj</code> is null then a <code>NullPointerException</code>
     * is thrown.
     *
     * @param      fdObj   the file descriptor to be opened for reading.
     * @throws     SecurityException      if a security manager exists and its
     *                 <code>checkRead</code> method denies read access to the
     *                 file descriptor.
     * @see        SecurityManager#checkRead(java.io.FileDescriptor)
     */
    public FileInputStream(FileDescriptor fdObj) {
	SecurityManager security = System.getSecurityManager();
	if (fdObj == null) {
	    throw new NullPointerException();
	}
	if (security != null) {
	    security.checkRead(fdObj);
	}
	fd = fdObj;

        /*
         * FileDescriptor is being shared by streams.
         * Ensure that it's GC'ed only when all the streams/channels are done
         * using it.
         */
        fd.incrementAndGetUseCount();
    }

    /**
     * Opens the specified file for reading.
     * @param name the name of the file
     */
    private native void open(String name) throws FileNotFoundException;

    /**
     * Reads a byte of data from this input stream. This method blocks
     * if no input is yet available.
     *
     * @return     the next byte of data, or <code>-1</code> if the end of the
     *             file is reached.
     * @exception  IOException  if an I/O error occurs.
     */
    public native int read() throws IOException;


    /**
     * Reads a subarray as a sequence of bytes.
     * @param b the data to be written
     * @param off the start offset in the data
     * @param len the number of bytes that are written
     * @exception IOException If an I/O error has occurred.
     */
    private native int readBytes(byte b[], int off, int len) throws IOException;

    /**
     * Reads up to <code>b.length</code> bytes of data from this input
     * stream into an array of bytes. This method blocks until some input
     * is available.
     *
     * @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 file has been reached.
     * @exception  IOException  if an I/O error occurs.
     */
    public int read(byte b[]) throws IOException {
	return readBytes(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.
     *
     * @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 file 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.
     */
    public int read(byte b[], int off, int len) throws IOException {
	return readBytes(b, off, len);
    }

    /**
     * Skips over and discards <code>n</code> bytes of data from the
     * input stream.
     *
     * <p>The <code>skip</code> method may, for a variety of
     * reasons, end up skipping over some smaller number of bytes,
     * possibly <code>0</code>. If <code>n</code> is negative, an
     * <code>IOException</code> is thrown, even though the <code>skip</code>
     * method of the {@link InputStream} superclass does nothing in this case.
     * The actual number of bytes skipped is returned.
     *
     * <p>This method may skip more bytes than are remaining in the backing
     * file. This produces no exception and the number of bytes skipped
     * may include some number of bytes that were beyond the EOF of the
     * backing file. Attempting to read from the stream after skipping past
     * the end will result in -1 indicating the end of the file.
     *
     * @param      n   the number of bytes to be skipped.
     * @return     the actual number of bytes skipped.
     * @exception  IOException  if n is negative, if the stream does not
     *                   support seek, or if an I/O error occurs.
     */
    public native long skip(long n) throws IOException;

    /**
     * Returns an estimate of the number of remaining bytes that can be read (or
     * skipped over) from this input stream without blocking by the next
     * invocation of a method for this input stream. The next invocation 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> In some cases, a non-blocking read (or skip) may appear to be
     * blocked when it is merely slow, for example when reading large
     * files over slow networks.
     *
     * @return     an estimate of the number of remaining bytes that can be read
     *             (or skipped over) from this input stream without blocking.
     * @exception  IOException  if this file input stream has been closed by calling
     *             {@code close} or an I/O error occurs.
     */
    public native int available() throws IOException;

    /**
     * Closes this file input stream and releases any system resources
     * associated with the stream.
     *
     * <p> If this stream has an associated channel then the channel is closed
     * as well.
     *
     * @exception  IOException  if an I/O error occurs.
     *
     * @revised 1.4
     * @spec JSR-51
     */
    public void close() throws IOException {
        synchronized (closeLock) {
            if (closed) {
                return;
            }
            closed = true;
        }
        if (channel != null) {
            /*
             * Decrement the FD use count associated with the channel
             * The use count is incremented whenever a new channel
             * is obtained from this stream.
             */
           fd.decrementAndGetUseCount();
           channel.close();
        }

        /*
         * Decrement the FD use count associated with this stream
         */
        int useCount = fd.decrementAndGetUseCount();

        /*
         * If FileDescriptor is still in use by another stream, the finalizer
         * will not close it.
         */
        if ((useCount <= 0) || !isRunningFinalize()) {
            close0();
        }
    }

    /**
     * Returns the <code>FileDescriptor</code>
     * object  that represents the connection to
     * the actual file in the file system being
     * used by this <code>FileInputStream</code>.
     *
     * @return     the file descriptor object associated with this stream.
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FileDescriptor
     */
    public final FileDescriptor getFD() throws IOException {
	if (fd != null) return fd;
	throw new IOException();
    }

    /**
     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
     * object associated with this file input stream.
     *
     * <p> The initial {@link java.nio.channels.FileChannel#position()
     * </code>position<code>} of the returned channel will be equal to the
     * number of bytes read from the file so far.  Reading bytes from this
     * stream will increment the channel's position.  Changing the channel's
     * position, either explicitly or by reading, will change this stream's
     * file position.
     *
     * @return  the file channel associated with this file input stream
     *
     * @since 1.4
     * @spec JSR-51
     */
    public FileChannel getChannel() {
	synchronized (this) {
	    if (channel == null) {
		channel = FileChannelImpl.open(fd, true, false, this);

                /*
                 * Increment fd's use count. Invoking the channel's close()
                 * method will result in decrementing the use count set for
                 * the channel.
                 */
                fd.incrementAndGetUseCount();

            }
	    return channel;
	}
    }

    private static native void initIDs();

    private native void close0() throws IOException;

    static {
	initIDs();
    }

    /**
     * Ensures that the <code>close</code> method of this file input stream is
     * called when there are no more references to it.
     *
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FileInputStream#close()
     */
    protected void finalize() throws IOException {
        if ((fd != null) &&  (fd != FileDescriptor.in)) {

            /*
             * Finalizer should not release the FileDescriptor if another
             * stream is still using it. If the user directly invokes
             * close() then the FileDescriptor is also released.
             */
            runningFinalize.set(Boolean.TRUE);
            try {
                close();
            } finally {
                runningFinalize.set(Boolean.FALSE);
            }
        }

    }
}



StringBufferInputString继承了InputString类型,同时持有一个对String对象的引用,这是一个将String对象适配成InputString类型的对象形式的适配器模式,如下图所示:
 

 OutputStream原始流处理器中的适配器模式
  同样地,在OutputStream类型中,所有的原始流处理器都是适配器类。
   ByteArrayOutputStream继承了OutputStream类型,同时持有一个对byte数组的引用。它一个byte数组的接口适配成OutputString类型的接口,因此也是一个对象形式的适配器模式的应用。
FileOutputStream是一个适配器类
FileOutputStream继承了OutputStream类型,同时持有一个对FileDiscriptor对象的引用。这是一个将FileDiscriptor接口适配成OutputStream接口形式的对象形适配器模式。
Reader原始流处理器中的适配器模式
Reader类型的原始流处理器都是适配器模式的应用。
StringReader是一个适配器类
StringReader类继承了Reader类型,持有一个对String对象的引用。它将String的接口适 配成Reader类型的接口,如下图所示:

从byte流到char流的适配
在Java I/O库中,使用比较频繁的要数InputStreamReader,OutputStreamWriter这两种类了,
InputStreamReader是从byte输入流到char输入流的一个适配器。下图所示就是 InputStreamReader与Reader和InputStream等类的结构图:

当把InputStreamReader与任何InputStream的具体子类链接的时候,可以从InputStream的输出读入byte类型的数据,将之转换成为char类型的数据
分享到:
评论

相关推荐

    PHP设计模式(五)适配器模式Adapter实例详解【结构型】

    适配器模式(Adapter Pattern)是一种结构型设计模式,它主要解决的是接口不兼容的问题,使得原本由于接口差异无法一起工作的类能够协同工作。在PHP中,适配器模式通过创建一个包装类(适配器类)来转换不兼容的接口...

    适配器模式adapter,含源码下载

    适配器模式(Adapter Pattern)是一种结构型设计模式,它能将两个不兼容的接口连接在一起,使得原本由于接口不匹配而无法一起工作的类能够协同工作。在IT行业中,适配器模式广泛应用在系统集成、组件重用以及解决...

    java 汽车适配器(Adapter适配器模式)

    适配器模式是一种软件设计模式,它允许两个不兼容的接口之间进行通信。在Java中,适配器模式被广泛应用于解决系统间的兼容性问题,尤其是当我们需要将一个已有的类库或者对象与我们的系统接口相匹配时。汽车适配器的...

    设计模式——适配器模式(adapter)

    适配器模式(Adapter Pattern)是软件设计模式中的一种,其主要目的是解决系统中的接口不兼容问题,使得原本由于接口不匹配而无法一起工作的类能够协同工作。在本文中,我们将深入探讨适配器模式的概念、结构、作用...

    设计模式C++学习之适配器模式(Adapter)

    适配器模式(Adapter)是软件工程中一种常用的设计模式,它允许两个不兼容的接口之间进行通信。在C++编程中,适配器模式能够帮助我们复用现有的类,或者将第三方库的接口与我们的系统接口进行对接,从而提高代码的可...

    设计模式之 适配器 Adapter C++ 源码

    设计模式之 适配器 Adapter C++ 源码 vs2019 工具,设计模式之 适配器 Adapter C++ 源码 vs2019 工具,设计模式之 适配器 Adapter C++ 源码 vs2019 工具,设计模式之 适配器 Adapter C++ 源码 vs2019 工具,设计模式...

    c++-设计模式之适配器模式(Adapter Pattern)

    适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个接口转换为客户端期望的另一个接口。适配器模式常用于解决由于接口不兼容而无法正常工作的类之间的协作问题。 适配器模式的组成 目标接口(Target...

    java设计模式之适配器模式

    适配器模式(Adapter Pattern)是通过创建一个新的对象(适配器),这个对象将原本不兼容的对象接口转换为客户端期望的接口,从而使两者能够协同工作。适配器模式可以分为类适配器和对象适配器两种类型。 1. 类...

    适配器(Adapter)模式

    适配器模式是一种软件设计模式,它允许两个不兼容的接口之间进行通信。在软件工程中,当系统中存在两种不兼容的接口或者类需要协同工作时,适配器模式可以发挥关键作用。通过适配器,我们可以复用现有的类,而无需...

    设计模式之适配器模式Java实现和类设计图

    文件列表中的"adapter"可能包含了适配器模式的Java源代码文件,这些文件通常会包含以上提到的三个角色的定义。例如,可能会有`Target.java`(目标接口),`Adaptee.java`(被适配者类),以及`Adapter.java`(类...

    适配器模式(Adapter)demo

    适配器模式是一种软件设计模式,它允许两个不兼容的接口之间进行通信。在软件开发中,我们常常遇到这样的情况:一个系统中的组件需要与另一个系统或库中的组件交互,但它们之间的接口不匹配,这时候就需要适配器模式...

    设计模式之适配器模式(Adapter Pattern)

    适配器模式是软件设计模式中的一种,它的主要目的是解决接口不兼容问题,使得原本由于接口差异无法协同工作的类能够协同工作。在实际的软件开发过程中,我们常常遇到这样的情况:旧有的系统或第三方库提供了丰富的...

    第9讲_适配器模式(Adapter)

    适配器模式是一种设计模式,它允许不兼容的类或接口之间进行通信和协作。这种模式的核心在于创建一个适配器类,该类将原始类(Adaptee)的接口转换为客户期望的目标接口(Target)。适配器模式分为基于类的适配器...

    设计模式之适配器模式

    2. 适配器(Adapter)类:这是适配器模式的核心,它实现了目标接口,并持有对适配者对象的引用。适配器类负责将适配者的接口转换为目标接口。 3. 适配者(Adaptee)类:这是需要适配的原始接口或类,它的接口与目标...

    适配器模式demo源码

    适配器模式是一种常用的设计模式,它在软件开发中起到了桥梁的作用,允许两个不兼容的接口之间进行通信。在这个“适配器模式demo源码”中,我们可以深入理解这一模式的实现方式及其应用场景。 适配器模式的核心思想...

    设计模式 之 “适配器模式[Adapter Pattern]”

    适配器模式(Adapter Pattern)是软件设计模式中的一种,其主要目的是使两个不兼容的接口之间能够协同工作。在IT行业中,我们经常遇到不同系统、库或组件之间的接口不一致,导致它们无法直接交互。适配器模式就提供...

    设计模式 - 适配器模式(C++实例)

    在`DesignMode_Adapter`这个压缩包文件中,可能包含了相关的C++源码示例,演示了如何创建和使用适配器模式。这些源码可能包括了目标接口、原始接口、适配器类的定义以及客户端如何通过适配器进行调用的示例。通过...

    Adapter(适配器模式)

    适配器模式是一种软件设计模式,它允许两个不兼容的接口之间进行通信。在软件工程中,当系统中存在已有的类或库,而我们希望使用它们的功能,但其接口与我们的需求不匹配时,适配器模式就显得尤为重要。通过适配器,...

Global site tag (gtag.js) - Google Analytics