htsjdk SamReader接口介绍

news2024/9/23 16:15:03

SamReader 是 htsjdk 库中的一个接口,用于读取和解析 SAM(Sequence Alignment/Map)和 BAM(Binary Alignment/Map)格式的文件。htsjdk 是一个广泛使用的 Java 库,提供了处理高通量测序数据的工具,SamReader 是其中的一个核心接口。

SamReader 接口介绍

SamReader 主要用于读取和迭代 SAM/BAM 文件中的记录(即比对信息)。它的设计使得用户可以方便地处理大规模的测序数据,同时支持随机访问、顺序读取、查询指定区间的数据等操作。

主要功能包括:

  • 顺序读取:逐条读取文件中的比对记录。
  • 区间查询:通过给定的染色体位置区间,获取对应的比对记录。
  • 元数据访问:获取 SAM/BAM 文件中的头信息(如参考序列、比对工具版本等)。
  • 文件索引支持:支持使用 BAM 索引文件(.bai)进行快速的区域查询。

SamReader内部接口/内部类

内部类 Type
  • 用于描述 SAM 文件的类型,例如 BAM、CRAM、SAM 等。
  • 每种类型都定义了一个文件扩展名和(可选的)索引扩展名。
内部接口 Indexing
  • 处理与索引相关的操作,例如获取索引、判断是否有可浏览的索引等。
PrimitiveSamReader 接口
  • 这是一个简化版的 SamReader,仅包含最基本的功能。通过 PrimitiveSamReaderToSamReaderAdapter 类可以将其转化为 SamReader
PrimitiveSamReaderToSamReaderAdapter 类
  • 这是一个适配器类,用于将 PrimitiveSamReader 转换为 SamReader
  • 该类实现了 SamReader 和 Indexing 接口,并且提供了一些辅助方法,例如 queryMate,用于查询配对读(paired read)的伴读(mate)。
   ReaderImplementation抽象类
  •         abstract class ReaderImplementation implements PrimitiveSamReader
  •         继承类为:

SamReader源码

/*
 * The MIT License
 *
 * Copyright (c) 2016 The Broad Institute
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package htsjdk.samtools;

import htsjdk.samtools.util.CloseableIterator;

import java.io.Closeable;
import java.text.MessageFormat;

/**
 * Describes functionality for objects that produce {@link SAMRecord}s and associated information.
 *
 * Currently, only deprecated readers implement this directly; actual readers implement this
 * via {@link ReaderImplementation} and {@link PrimitiveSamReader}, which {@link SamReaderFactory}
 * converts into full readers by using {@link PrimitiveSamReaderToSamReaderAdapter}.
 *
 * @author mccowan
 */
public interface SamReader extends Iterable<SAMRecord>, Closeable {

    /** Describes a type of SAM file. */
    public abstract class Type {
        /** A string representation of this type. */
        public abstract String name();

        /** The recommended file extension for SAMs of this type, without a period. */
        public abstract String fileExtension();

        /** The recommended file extension for SAM indexes of this type, without a period, or null if this type is not associated with indexes. */
        public abstract String indexExtension();

        static class TypeImpl extends Type {
            final String name, fileExtension, indexExtension;

            TypeImpl(final String name, final String fileExtension, final String indexExtension) {
                this.name = name;
                this.fileExtension = fileExtension;
                this.indexExtension = indexExtension;
            }

            @Override
            public String name() {
                return name;
            }

            @Override
            public String fileExtension() {
                return fileExtension;
            }

            @Override
            public String indexExtension() {
                return indexExtension;
            }

            @Override
            public String toString() {
                return String.format("TypeImpl{name='%s', fileExtension='%s', indexExtension='%s'}", name, fileExtension, indexExtension);
            }
        }

        public static final Type SRA_TYPE = new TypeImpl("SRA", "sra", null);
        public static final Type CRAM_TYPE = new TypeImpl("CRAM", "cram", "crai");
        public static final Type BAM_TYPE = new TypeImpl("BAM", "bam", "bai");
        public static final Type SAM_TYPE = new TypeImpl("SAM", "sam", null);
        public static final Type BAM_CSI_TYPE = new TypeImpl("BAM", "bam", "csi");
        public static final Type BAM_HTSGET_TYPE = new TypeImpl("BAM", "bam", null);

        public boolean hasValidFileExtension(final String fileName) {
            return fileName != null && fileName.endsWith("." + fileExtension());
        }
    }

    /**
     * Facet for index-related operations.
     */
    public interface Indexing {
        /**
         * Retrieves the index for the given file type.  Ensure that the index is of the specified type.
         *
         * @return An index of the given type.
         */
        public BAMIndex getIndex();

        /**
         * Returns true if the supported index is browseable, meaning the bins in it can be traversed
         * and chunk data inspected and retrieved.
         *
         * @return True if the index supports the BrowseableBAMIndex interface.  False otherwise.
         */
        public boolean hasBrowseableIndex();

        /**
         * Gets an index tagged with the BrowseableBAMIndex interface.  Throws an exception if no such
         * index is available.
         *
         * @return An index with a browseable interface, if possible.
         * @throws SAMException if no such index is available.
         */
        public BrowseableBAMIndex getBrowseableIndex();

        /**
         * Iterate through the given chunks in the file.
         *
         * @param chunks List of chunks for which to retrieve data.
         * @return An iterator over the given chunks.
         */
        public SAMRecordIterator iterator(final SAMFileSpan chunks);

        /**
         * Gets a pointer spanning all reads in the BAM file.
         *
         * @return Unbounded pointer to the first record, in chunk format.
         */
        public SAMFileSpan getFilePointerSpanningReads();

    }

    public SAMFileHeader getFileHeader();

    /**
     * @return the {@link htsjdk.samtools.SamReader.Type} of this {@link htsjdk.samtools.SamReader}
     */
    public Type type();

    /**
     * @return a human readable description of the resource backing this sam reader
     */
    public String getResourceDescription();

    /**
     * @return true if this source can be queried by interval, regardless of whether it has an index
     */
    default public boolean isQueryable() {
        return this.hasIndex();
    }

    /**
     * @return true if ths is a BAM file, and has an index
     */
    public boolean hasIndex();

    /**
     * Exposes the {@link SamReader.Indexing} facet of this {@link SamReader}.
     *
     * @throws java.lang.UnsupportedOperationException If {@link #hasIndex()} returns false.
     */
    public Indexing indexing();

    /**
     * Iterate through file in order.  For a SamReader constructed from an InputStream, and for any SAM file,
     * a 2nd iteration starts where the 1st one left off.  For a BAM constructed from a SeekableStream or File, each new iteration
     * starts at the first record.
     * <p/>
     * Only a single open iterator on a SAM or BAM file may be extant at any one time.  If you want to start
     * a second iteration, the first one must be closed first.
     */
    @Override
    public SAMRecordIterator iterator();

    /**
     * Iterate over records that match the given interval.  Only valid to call this if hasIndex() == true.
     * <p/>
     * Only a single open iterator on a given SamReader may be extant at any one time.  If you want to start
     * a second iteration, the first one must be closed first.  You can use a second SamReader to iterate
     * in parallel over the same underlying file.
     * <p/>
     * Note that indexed lookup is not perfectly efficient in terms of disk I/O.  I.e. some SAMRecords may be read
     * and then discarded because they do not match the interval of interest.
     * <p/>
     * Note that an unmapped read will be returned by this call if it has a coordinate for the purpose of sorting that
     * is in the query region.
     *
     * @param sequence  Reference sequence of interest.
     * @param start     1-based, inclusive start of interval of interest. Zero implies start of the reference sequence.
     * @param end       1-based, inclusive end of interval of interest. Zero implies end of the reference sequence.
     * @param contained If true, each SAMRecord returned will have its alignment completely contained in the
     *                  interval of interest.  If false, the alignment of the returned SAMRecords need only overlap the interval of interest.
     * @return Iterator over the SAMRecords matching the interval.
     */
    public SAMRecordIterator query(final String sequence, final int start, final int end, final boolean contained);

    /**
     * Iterate over records that overlap the given interval.  Only valid to call this if hasIndex() == true.
     * <p/>
     * Only a single open iterator on a given SamReader may be extant at any one time.  If you want to start
     * a second iteration, the first one must be closed first.
     * <p/>
     * Note that indexed lookup is not perfectly efficient in terms of disk I/O.  I.e. some SAMRecords may be read
     * and then discarded because they do not match the interval of interest.
     * <p/>
     * Note that an unmapped read will be returned by this call if it has a coordinate for the purpose of sorting that
     * is in the query region.
     *
     * @param sequence Reference sequence of interest.
     * @param start    1-based, inclusive start of interval of interest. Zero implies start of the reference sequence.
     * @param end      1-based, inclusive end of interval of interest. Zero implies end of the reference sequence.
     * @return Iterator over the SAMRecords overlapping the interval.
     */
    public SAMRecordIterator queryOverlapping(final String sequence, final int start, final int end);

    /**
     * Iterate over records that are contained in the given interval.  Only valid to call this if hasIndex() == true.
     * <p/>
     * Only a single open iterator on a given SamReader may be extant at any one time.  If you want to start
     * a second iteration, the first one must be closed first.
     * <p/>
     * Note that indexed lookup is not perfectly efficient in terms of disk I/O.  I.e. some SAMRecords may be read
     * and then discarded because they do not match the interval of interest.
     * <p/>
     * Note that an unmapped read will be returned by this call if it has a coordinate for the purpose of sorting that
     * is in the query region.
     *
     * @param sequence Reference sequence of interest.
     * @param start    1-based, inclusive start of interval of interest. Zero implies start of the reference sequence.
     * @param end      1-based, inclusive end of interval of interest. Zero implies end of the reference sequence.
     * @return Iterator over the SAMRecords contained in the interval.
     */
    public SAMRecordIterator queryContained(final String sequence, final int start, final int end);

    /**
     * Iterate over records that match one of the given intervals.  This may be more efficient than querying
     * each interval separately, because multiple reads of the same SAMRecords is avoided.
     * <p/>
     * Only valid to call this if hasIndex() == true.
     * <p/>
     * Only a single open iterator on a given SamReader may be extant at any one time.  If you want to start
     * a second iteration, the first one must be closed first.  You can use a second SamReader to iterate
     * in parallel over the same underlying file.
     * <p/>
     * Note that indexed lookup is not perfectly efficient in terms of disk I/O.  I.e. some SAMRecords may be read
     * and then discarded because they do not match an interval of interest.
     * <p/>
     * Note that an unmapped read will be returned by this call if it has a coordinate for the purpose of sorting that
     * is in the query region.
     *
     * @param intervals Intervals to be queried.  The intervals must be optimized, i.e. in order, with overlapping
     *                  and abutting intervals merged.  This can be done with {@link htsjdk.samtools.QueryInterval#optimizeIntervals}
     * @param contained If true, each SAMRecord returned is will have its alignment completely contained in one of the
     *                  intervals of interest.  If false, the alignment of the returned SAMRecords need only overlap one of
     *                  the intervals of interest.
     * @return Iterator over the SAMRecords matching the interval.
     */
    public SAMRecordIterator query(final QueryInterval[] intervals, final boolean contained);

    /**
     * Iterate over records that overlap any of the given intervals.  This may be more efficient than querying
     * each interval separately, because multiple reads of the same SAMRecords is avoided.
     * <p/>
     * Only valid to call this if hasIndex() == true.
     * <p/>
     * Only a single open iterator on a given SamReader may be extant at any one time.  If you want to start
     * a second iteration, the first one must be closed first.
     * <p/>
     * Note that indexed lookup is not perfectly efficient in terms of disk I/O.  I.e. some SAMRecords may be read
     * and then discarded because they do not match the interval of interest.
     * <p/>
     * Note that an unmapped read will be returned by this call if it has a coordinate for the purpose of sorting that
     * is in the query region.
     *
     * @param intervals Intervals to be queried.  The intervals must be optimized, i.e. in order, with overlapping
     *                  and abutting intervals merged.  This can be done with {@link htsjdk.samtools.QueryInterval#optimizeIntervals}
     */
    public SAMRecordIterator queryOverlapping(final QueryInterval[] intervals);

    /**
     * Iterate over records that are contained in the given interval.  This may be more efficient than querying
     * each interval separately, because multiple reads of the same SAMRecords is avoided.
     * <p/>
     * Only valid to call this if hasIndex() == true.
     * <p/>
     * Only a single open iterator on a given SamReader may be extant at any one time.  If you want to start
     * a second iteration, the first one must be closed first.
     * <p/>
     * Note that indexed lookup is not perfectly efficient in terms of disk I/O.  I.e. some SAMRecords may be read
     * and then discarded because they do not match the interval of interest.
     * <p/>
     * Note that an unmapped read will be returned by this call if it has a coordinate for the purpose of sorting that
     * is in the query region.
     *
     * @param intervals Intervals to be queried.  The intervals must be optimized, i.e. in order, with overlapping
     *                  and abutting intervals merged.  This can be done with {@link htsjdk.samtools.QueryInterval#optimizeIntervals}
     * @return Iterator over the SAMRecords contained in any of the intervals.
     */
    public SAMRecordIterator queryContained(final QueryInterval[] intervals);


    public SAMRecordIterator queryUnmapped();

    /**
     * Iterate over records that map to the given sequence and start at the given position.  Only valid to call this if hasIndex() == true.
     * <p/>
     * Only a single open iterator on a given SamReader may be extant at any one time.  If you want to start
     * a second iteration, the first one must be closed first.
     * <p/>
     * Note that indexed lookup is not perfectly efficient in terms of disk I/O.  I.e. some SAMRecords may be read
     * and then discarded because they do not match the interval of interest.
     * <p/>
     * Note that an unmapped read will be returned by this call if it has a coordinate for the purpose of sorting that
     * matches the arguments.
     *
     * @param sequence Reference sequence of interest.
     * @param start    Alignment start of interest.
     * @return Iterator over the SAMRecords with the given alignment start.
     */
    public SAMRecordIterator queryAlignmentStart(final String sequence, final int start);

    /**
     * Fetch the mate for the given read.  Only valid to call this if hasIndex() == true.
     * This will work whether the mate has a coordinate or not, so long as the given read has correct
     * mate information.  This method iterates over the SAM file, so there may not be an unclosed
     * iterator on the SAM file when this method is called.
     * <p/>
     * Note that it is not possible to call queryMate when iterating over the SamReader, because queryMate
     * requires its own iteration, and there cannot be two simultaneous iterations on the same SamReader.  The
     * work-around is to open a second SamReader on the same input file, and call queryMate on the second
     * reader.
     *
     * @param rec Record for which mate is sought.  Must be a paired read.
     * @return rec's mate, or null if it cannot be found.
     */
    public SAMRecord queryMate(final SAMRecord rec);

    /**
     * The minimal subset of functionality needed for a {@link SAMRecord} data source.
     * {@link SamReader} itself is somewhat large and bulky, but the core functionality can be captured in
     * relatively few methods, which are included here. For documentation, see the corresponding methods
     * in {@link SamReader}.
     *
     * See also: {@link PrimitiveSamReaderToSamReaderAdapter}, {@link ReaderImplementation}
     *
     */
    public interface PrimitiveSamReader {
        Type type();

        default boolean isQueryable() {
            return this.hasIndex();
        }

        boolean hasIndex();

        BAMIndex getIndex();

        SAMFileHeader getFileHeader();

        CloseableIterator<SAMRecord> getIterator();

        CloseableIterator<SAMRecord> getIterator(SAMFileSpan fileSpan);

        SAMFileSpan getFilePointerSpanningReads();

        CloseableIterator<SAMRecord> query(QueryInterval[] intervals, boolean contained);

        CloseableIterator<SAMRecord> queryAlignmentStart(String sequence, int start);

        CloseableIterator<SAMRecord> queryUnmapped();

        void close();

        ValidationStringency getValidationStringency();
    }

    /**
     * Decorator for a {@link SamReader.PrimitiveSamReader} that expands its functionality into a {@link SamReader},
     * given the backing {@link SamInputResource}.
     *
     * Wraps the {@link Indexing} interface as well, which was originally separate from {@link SamReader} but in practice
     * the two are always implemented by the same class.
     *
     */
    class PrimitiveSamReaderToSamReaderAdapter implements SamReader, Indexing {
        final PrimitiveSamReader p;
        final SamInputResource resource;

        public PrimitiveSamReaderToSamReaderAdapter(final PrimitiveSamReader p, final SamInputResource resource) {
            this.p = p;
            this.resource = resource;
        }

        /**
         * Access the underlying {@link PrimitiveSamReader} used by this adapter.
         * @return the {@link PrimitiveSamReader} used by this adapter.
         */
        public PrimitiveSamReader underlyingReader() {
            return p;
        }

        @Override
        public SAMRecordIterator queryOverlapping(final String sequence, final int start, final int end) {
            return query(sequence, start, end, false);
        }

        @Override
        public SAMRecordIterator queryOverlapping(final QueryInterval[] intervals) {
            return query(intervals, false);
        }

        @Override
        public SAMRecordIterator queryContained(final String sequence, final int start, final int end) {
            return query(sequence, start, end, true);
        }

        @Override
        public SAMRecordIterator queryContained(final QueryInterval[] intervals) {
            return query(intervals, true);
        }

        /**
         * Wraps the boilerplate code for querying a record's mate, which is common across many implementations.
         *
         * @param rec Record for which mate is sought.  Must be a paired read.
         * @return
         */
        @Override
        public SAMRecord queryMate(final SAMRecord rec) {
            if (!rec.getReadPairedFlag()) {
                throw new IllegalArgumentException("queryMate called for unpaired read.");
            }
            if (rec.getFirstOfPairFlag() == rec.getSecondOfPairFlag()) {
                throw new IllegalArgumentException("SAMRecord must be either first and second of pair, but not both.");
            }
            final boolean firstOfPair = rec.getFirstOfPairFlag();
            final CloseableIterator<SAMRecord> it;
            if (rec.getMateReferenceIndex() == SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX) {
                it = queryUnmapped();
            } else {
                it = queryAlignmentStart(rec.getMateReferenceName(), rec.getMateAlignmentStart());
            }
            try {
                SAMRecord mateRec = null;
                while (it.hasNext()) {
                    final SAMRecord next = it.next();
                    if (!next.getReadPairedFlag()) {
                        if (rec.getReadName().equals(next.getReadName())) {
                            throw new SAMFormatException("Paired and unpaired reads with same name: " + rec.getReadName());
                        }
                        continue;
                    }
                    if (firstOfPair) {
                        if (next.getFirstOfPairFlag()) continue;
                    } else {
                        if (next.getSecondOfPairFlag()) continue;
                    }
                    if (rec.getReadName().equals(next.getReadName())) {
                        if (mateRec != null) {
                            throw new SAMFormatException("Multiple SAMRecord with read name " + rec.getReadName() +
                                    " for " + (firstOfPair ? "second" : "first") + " end.");
                        }
                        mateRec = next;
                    }
                }
                return mateRec;
            } finally {
                it.close();
            }
        }

        @Override
        public boolean hasBrowseableIndex() {
            return hasIndex() && getIndex() instanceof BrowseableBAMIndex;
        }

        @Override
        public BrowseableBAMIndex getBrowseableIndex() {
            final BAMIndex index = getIndex();
            if (!(index instanceof BrowseableBAMIndex))
                throw new SAMException("Cannot return index: index created by BAM is not browseable.");
            return BrowseableBAMIndex.class.cast(index);
        }

        @Override
        public SAMRecordIterator iterator() {
            return new AssertingIterator(p.getIterator());
        }

        @Override
        public SAMRecordIterator iterator(final SAMFileSpan chunks) {
            return new AssertingIterator(p.getIterator(chunks));
        }

        @Override
        public void close() {
            p.close();
        }

        @Override
        public SAMFileSpan getFilePointerSpanningReads() {
            return p.getFilePointerSpanningReads();
        }

        @Override
        public SAMFileHeader getFileHeader() {
            return p.getFileHeader();
        }

        @Override
        public Type type() {
            return p.type();
        }

        @Override
        public String getResourceDescription() {
            return this.resource.toString();
        }

        @Override
        public boolean isQueryable() {
            return p.isQueryable();
        }

        @Override
        public boolean hasIndex() {
            return p.hasIndex();
        }

        @Override
        public Indexing indexing() {
            return this;
        }

        @Override
        public BAMIndex getIndex() {
            return p.getIndex();
        }

        @Override
        public SAMRecordIterator query(final QueryInterval[] intervals, final boolean contained) {
            return AssertingIterator.of(p.query(intervals, contained));
        }

        @Override
        public SAMRecordIterator query(final String sequence, final int start, final int end, final boolean contained) {
            return query(new QueryInterval[]{new QueryInterval(getFileHeader().getSequenceIndex(sequence), start, end)}, contained);
        }

        @Override
        public SAMRecordIterator queryUnmapped() {
            return AssertingIterator.of(p.queryUnmapped());
        }

        @Override
        public SAMRecordIterator queryAlignmentStart(final String sequence, final int start) {
            return AssertingIterator.of(p.queryAlignmentStart(sequence, start));
        }

    }

    static class AssertingIterator implements SAMRecordIterator {

        static AssertingIterator of(final CloseableIterator<SAMRecord> iterator) {
            return new AssertingIterator(iterator);
        }

        private final CloseableIterator<SAMRecord> wrappedIterator;
        private SAMSortOrderChecker checker;

        public AssertingIterator(final CloseableIterator<SAMRecord> iterator) {
            wrappedIterator = iterator;
        }

        @Override
        public SAMRecordIterator assertSorted(final SAMFileHeader.SortOrder sortOrder) {
            checker = new SAMSortOrderChecker(sortOrder);
            return this;
        }

        @Override
        public SAMRecord next() {
            final SAMRecord result = wrappedIterator.next();
            if (checker != null) {
                final SAMRecord previous = checker.getPreviousRecord();
                if (!checker.isSorted(result)) {
                    throw new IllegalStateException(String.format(
                            "Record %s should come after %s when sorting with %s ordering.",
                            previous.getSAMString().trim(),
                            result.getSAMString().trim(), checker.getSortOrder()));
                }
            }
            return result;
        }

        @Override
        public void close() { wrappedIterator.close(); }

        @Override
        public boolean hasNext() { return wrappedIterator.hasNext(); }

        @Override
        public void remove() { wrappedIterator.remove(); }
    }

    /**
     * Internal interface for SAM/BAM/CRAM file reader implementations,
     * as distinct from non-file-based readers.
     *
     * Implemented as an abstract class to enforce better access control.
     *
     * TODO -- Many of these methods only apply for a subset of implementations,
     * TODO -- and either no-op or throw an exception for the others.
     * TODO -- We should consider refactoring things to avoid this;
     * TODO -- perhaps we can get away with not having this class at all.
     */
    abstract class ReaderImplementation implements PrimitiveSamReader {
        abstract void enableFileSource(final SamReader reader, final boolean enabled);

        abstract void enableIndexCaching(final boolean enabled);

        abstract void enableIndexMemoryMapping(final boolean enabled);

        abstract void enableCrcChecking(final boolean enabled);

        abstract void setSAMRecordFactory(final SAMRecordFactory factory);

        abstract void setValidationStringency(final ValidationStringency validationStringency);
    }
}

注:

在复杂的软件系统中,尤其是像处理 SAM/BAM 等复杂生物信息学数据的系统中,定义一个多层次、复杂的接口层次结构可以带来几个重要的好处:

  • 灵活性:通过使用多个内部接口和类,设计者可以在不改变公共 API 的情况下,轻松地扩展和修改内部实现。例如,如果未来需要对 PrimitiveSamReader 的行为进行重大更改,只需要修改它及相关的适配器类,而不必改变整个系统。

  • 分离关注点:复杂的接口设计可以帮助将不同的功能模块化。例如,将索引功能 (Indexing) 与基本的 SAM 读取功能 (PrimitiveSamReader) 分开,使得每个模块关注自己的职责。

  • 适配不同的实现:通过适配器模式(PrimitiveSamReaderToSamReaderAdapter),可以将一个接口(或实现)转化为另一个接口的实现,从而允许系统通过组合或扩展的方式来实现不同的功能组合。这种方式为代码的复用和扩展提供了便利。

  • 接口稳定性:定义复杂接口的目的是为了在未来扩展时尽量保持现有接口的稳定性和兼容性。这样,用户代码可以依赖于稳定的 API,而不必担心底层实现的变化。

总的来说,这种设计不仅是规范的,而且还遵循了面向对象设计中的几个重要原则,如单一职责原则、开闭原则和接口分离原则等。这种设计方法确保了代码的灵活性、可维护性和扩展性,特别是在像 htsjdk 这样复杂的库中。

BAMFileReader源码

/*
 * The MIT License
 *
 * Copyright (c) 2009 The Broad Institute
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package htsjdk.samtools;


import htsjdk.samtools.seekablestream.SeekableStream;
import htsjdk.samtools.util.*;
import htsjdk.samtools.util.zip.InflaterFactory;

import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import j

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2068143.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

也开发一点自己的agent框架

换了一份工作&#xff0c;抽空写一篇文章。 前面说自己看了ja-netfilter&#xff0c;这个作者肯定是个厉害的人&#xff0c;但是在项目工程化方面&#xff0c;做出来的东西未必好用是真的&#xff0c;不是diss别人&#xff0c;而是他的插件接口还是指令集的。说实话&#xff0c…

TCP BBR 数学模型完整版

今天顺带加入了 bbr 的所有状态和所有流程&#xff0c;获得以下的方程组&#xff1a; C Bltbw&#xff0c;R RtProp&#xff0c;T_r ProbeRTT 周期&#xff0c;g1 Startup gain&#xff0c;g2 ProbeBW gain。设 x estimated bandwidth&#xff0c;r round trip time&am…

【STM32】C语言基础补充

学习过程中发现自己好些需要用到的C语言语法、特征都不太熟练了&#xff0c;特意记录一下&#xff0c;免得忘记了&#xff0c;以后遇到了新的也会继续更新 目录 1 全局变量 2 结构体 3 静态变量 4 memset()函数 5 使用8位的存储器存16位的数 1 全局变量…

vue3 Props的用法(父传子)

在 Vue 3 中&#xff0c;Props&#xff08;属性&#xff09;用于在组件之间传递数据。 Props的作用 传参&#xff1a;Props 允许父组件向子组件传递数据。类型检查&#xff1a;Vue 允许在定义 Props 时指定数据的类型&#xff0c;这有助于在开发过程中进行类型检查&#xff0…

Nextjs(App Router) 开发记录

最近业余在开发一款智能助理产品&#xff0c;记录开发过程中的一些问题以备忘&#xff0c;也是帮其他人防坑。 主要技术栈 本项目采用了前沿的技术栈来构建一个高性能且可维护的应用。选择了 Nx 作为构建管理和单一代码库解决方案&#xff0c;通过模块化和插件系统来扩展和优…

开源的个人独立博客Moments社交优化项目源码

开源的个人独立博客Moments社交优化项目源码&#xff0c;为你提供了一个与关注的博客作者和读者互动的全新方式&#xff0c;让你的博客体验更加丰富和充实。 Moments的核心目标是通过整合各种订阅源&#xff0c;如RSS和Atom&#xff0c;将你感兴趣的博客转化为一个个人朋友圈。…

日志排查——linux

目录 介绍步骤 介绍 /var/log/wtmp&#xff1a;记录登录进入、退出、数据交换、关机和重启&#xff0c;即last。 /var/log/cron&#xff1a;记录与定时任务相关的日志信息。 /var/log/messages&#xff1a;记录系统启动后的信息和错误日志。 /var/log/apache2/access.log&a…

你不知道的console方法

JavaScript为我们提供了一个内置的调试工具&#xff0c;即控制台(console)&#xff0c;使开发人员能够测试、调试和与他们的网页进行交互。JavaScript的控制台对象中有几种可用的方法&#xff0c;每种方法都有不同的用途。本文将讨论这些方法&#xff0c;并提供它们的使用示例。…

计算机毕业设计 学院网站 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

Linux中解决 zfs 安装后无法加载和使用,报错类似如下:modprobe: FATAL: Module zfs not found.

Linux中解决 zfs 安装后无法加载和使用&#xff0c;报错类似如下&#xff1a;modprobe: FATAL: Module zfs not found. # modprobe zfs modprobe: FATAL: Module zfs not found.解决办法&#xff1a; yum remove zfs spl kmod-zfs -yyum update -y --skip-brokenos_v$(cat /et…

文献翻译什么软件好?文献翻译全文软件推荐这5个

处暑已过&#xff0c;秋风渐起&#xff0c;知识的田野也迎来了收获的季节。在学术研究的旅途中&#xff0c;我们常常需要跨越语言的界限&#xff0c;探寻远方的智慧。 每当面对厚重的外文文献&#xff0c;应该如何快速准确地转化为可读的中文呢&#xff1f;其实只要选择一款高…

加速指南:如何使用Kimi提升论文写作效率?

在学术研究领域&#xff0c;撰写论文是一项基础且关键的任务&#xff0c;它要求作者不仅要有扎实的专业知识&#xff0c;还要具备高效的信息处理能力和清晰的表达技巧。学术写作是一个复杂的过程&#xff0c;涉及多个阶段&#xff1a;从选题、资料搜集、论文结构设计&#xff0…

STM32(五):定时器——输出比较

定时器输出比较功能&#xff1a;输出PWM波形 OC&#xff08;Output Compare&#xff09;输出比较 输出比较可以通过比较CNT与CCR寄存器值的关系&#xff0c;来对输出电平进行置1、置0或翻转的操作&#xff0c;用于输出一定频率和占空比的PWM波形。 每个高级定时器和通用定时器…

【硬件模块】红外跟随避障模块

红外跟随避障模块实物图 红外避障模块不断发射红外信号&#xff0c;当红外信号&#xff1a; 有反射回来&#xff0c;OUT 输出低电平&#xff0c;输出指示灯&#xff08;绿灯&#xff09;亮&#xff1b; 没反射回来&#xff0c;OUT 输出高电平&#xff0c;输出指示灯&#xff08…

tcp通信以及wireshark抓包

loop: //本地回环测试 tcp在传输时&#xff0c;有可能就会将两次发送的内容粘到一起&#xff0c;这是由于tcp的第三个特点&#xff1a;字节流式传输。它不一定会将两次发送出来的数据进行严格区分。这种现象在tcp链接中叫粘包。 但是socket在底层发送东西的时候是会在一段时间…

【微信小程序】使用 npm 包 - API Promise化-- miniprogram-api-promise

1. 基于回调函数的异步 API 的缺点 默认情况下&#xff0c;小程序官方提供的异步 API 都是基于回调函数实现的&#xff0c;例如&#xff0c;网络请求的 API 需要按照如下的方式调用&#xff1a; 缺点&#xff1a;容易造成回调地狱的问题&#xff0c;代码的可读性、维护性差&a…

I2C软件模拟与Delay寄存器延迟函数

环境 芯片:STM32F103ZET6 库&#xff1a;来自HAL的STM32F1XX.H 原理图 有图可知SCL和SDA两条线接到了PB10和PB11 Driver_I2C.h #ifndef __DRIVER_I2C #define __DRIVER_I2C#include "stm32f1xx.h" #include "Com_Delay.h" // 定义拉高SCL引脚的宏操作 #…

【电子数据取证】应用程序提取及固定

文章关键词&#xff1a;电子数据取证、手机取证、计算机取证、计算机仿真、云取证 一、前言 在数字化时代&#xff0c;电子数据已成为现代社会不可或缺的一部分&#xff0c;它不仅记录着个人的日常生活轨迹&#xff0c;也承载着企业运营的核心信息&#xff0c;更在司法体系中…

Nginx知识详解(理论+实战更易懂)

目录 一、Nginx架构和安装 1.1 Nginx 概述 1.1.1 nginx介绍 1.1.2 Nginx 功能介绍 1.1.3 基础特性 1.1.4 Web 服务相关的功能 1.2 Nginx 架构和进程 1.2.1 Nginx 进程结构 1.2.2 Nginx 进程间通信 1.2.3 Nginx 启动和 HTTP 连接建立 1.2.4 HTTP 处理过程 1.3 Nginx …

pdf转换成excel在线转换?这3款别错过

作为一名财务人员&#xff0c;我每天的工作都离不开处理大量的文件和数据。其中&#xff0c;将PDF格式的报表转换成Excel表格是一项经常要做的工作。在众多的PDF转换工具中&#xff0c;我试过了三款PDF转换工具&#xff0c;现在就来分享一下我的使用体验。 一、福昕PDF转换大师…