適配器模式-文件服務

前言

適配器模式是把一個類的接口變換成客戶端所期待的另一中接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作庆冕。
用電器做例子,筆記本電腦的插頭一般都是三相的,即除了陽極批旺、陰極外,還有一個地極诵姜。而有些地方的電源插座卻只有兩極汽煮,沒有地極。電源插座與筆記本電腦的電源插頭不匹配使得筆記本電腦無法使用茅诱。這時候一個三相到兩相的轉(zhuǎn)換器(適配器)就能解決此問題逗物,而這正像是本模式所做的事情(這個例子是我抄來的)。

適配器模式的類型

關(guān)于適配器模式的類型這個小節(jié)太過枯燥無味瑟俭,概念定義生搬硬套太過牽強令人難以理解翎卓,雖然基本是我復制粘貼的過來的但是仍一度讓我惱火到不想繼續(xù)寫下去。建議大家跳過這一部分直接看下面具體的業(yè)務場景摆寄。

適配器模式有類的適配器和對象的適配器兩種不同的形式失暴。

  • 類適配器
    image.png

類的適配器模式把適配的類的API轉(zhuǎn)換成目標類的API,假設有一個接口A和一個具體的類B微饥,B不是A的實現(xiàn)類逗扒,現(xiàn)在客戶端希望在一個A的是實現(xiàn)類C中使用B的功能,最簡單的方法就是使C實現(xiàn)A的同時又繼承B欠橘。這其中涉及到了三個角色

  • 目標角色(target):就是所期待得到的目標接口A

  • 源角色(Adapee):現(xiàn)在要適配的類B

  • 適配器角色:
    適配器類是本模式的核心矩肩。適配器把源接口轉(zhuǎn)換成目標接口。顯然肃续,這一角色不可以 是接口黍檩,而必 須是具體類,在本例中C就是適配器

  • 對象適配器
    與類的適配器模式一樣始锚,對象的適配器模式把被適配的類的API轉(zhuǎn)換成為目標類的API刽酱,與類的適配器模式不同的是,對象的適配器模式不是使用繼承關(guān)系連接到Adaptee類瞧捌,而是使用委派關(guān)系連接到Adaptee類棵里。

    image.png

使用適配器模式實現(xiàn)文件服務

最近一個月都在做公司的項目遷移润文,把集團的項目(包括服務器)遷移到上海這邊,我們原有的框架下有一套自研的文件服務實現(xiàn)殿怜,是將文件內(nèi)容byte數(shù)組及元數(shù)據(jù)存放在mongo中典蝌,這個自研的文件服務有些年頭了而且引入了這個文件服務之后在項目啟動時會自動加載mongo連接(無論是否實際使用),重度依賴基礎環(huán)境头谜,所以趁著這次項目遷移準備完全移除自研的文件服務使用第三方文件服務實現(xiàn)赠法,最終選用了阿里云oss作為第三方文件服務實現(xiàn),以下就用oss表示新的文件服務乔夯。
因為要考慮到歷史文件的遷移砖织,文件服務遷移主要分成了兩個階段:
一、文件雙寫:
增量數(shù)據(jù)(新上傳的文件)雙寫末荐,同時上傳到自研文件服務和oss侧纯,同一個文件在自研文件服務和oss中的文件id是一致的,讀取文件仍然從自研文件服務中讀燃自唷(因為存量數(shù)據(jù)尚未同步至oss中)眶熬。
二、存量數(shù)據(jù)同步:
因為有很多文件id是作為歷史數(shù)據(jù)(存量數(shù)據(jù))保存在mysql中的各個業(yè)務表中的(比如營業(yè)執(zhí)照块请、合同等)娜氏,為了確保切換到oss后歷史文件能夠正確顯示,最簡單的方法就是將自研文件服務中的存量數(shù)據(jù)同步到oss中并且確保文件id一致墩新,這樣同步完成之后就能夠無縫切換到oss贸弥。

在文件雙寫階段要實現(xiàn)的目標是 使用新的文件服務依賴替代原有的自研框架的文件服務依賴,對外只暴露新的文件服務接口定義的接口和類(接口和類除了包路徑與自研服務不同之外海渊,接口名類名和參數(shù)名都完全相同绵疲,這樣各個依賴方只需要在導包處把包路徑替換即可無需改動代碼邏輯),所以這個時候就需要我們將自研的文件服務和新的文件服務做一個適配臣疑。
以下是代碼部分:
自研文件服務:

package com.cube.dp.adapter.fs.custom;

import com.cube.dp.adapter.fs.custom.dto.FileDownloadDto;
import com.cube.dp.adapter.fs.custom.dto.FileDownloadForStreamDto;
import com.cube.dp.adapter.fs.custom.dto.FileUploadDto;
import com.cube.dp.adapter.fs.custom.dto.FileUploadForStreamDto;

/**
 * @author litb
 * @date 2022/5/21 15:32
 * <p>
 * 自研文件服務接口
 */
public interface IFileOperationService {


    /**
     * 上傳文件
     *
     * @param dto 參數(shù)
     * @return 文件id
     */
    String upload(FileUploadDto dto);

    /**
     * 流式上傳文件
     *
     * @param streamDto 參數(shù)
     * @return 文件id
     */
    String upload4Stream(FileUploadForStreamDto streamDto);

    /**
     * 下載文件
     *
     * @param fileId 文件id
     * @return 結(jié)果
     */
    FileDownloadDto download(String fileId);

    /**
     * 流式下載文件
     *
     * @param fileId 文件id
     * @return 結(jié)果
     */
    FileDownloadForStreamDto download4Stream(String fileId);
}

自研文件服務實現(xiàn)類

package com.cube.dp.adapter.fs.custom;

import com.cube.dp.adapter.fs.custom.dto.FileDownloadDto;
import com.cube.dp.adapter.fs.custom.dto.FileDownloadForStreamDto;
import com.cube.dp.adapter.fs.custom.dto.FileUploadDto;
import com.cube.dp.adapter.fs.custom.dto.FileUploadForStreamDto;

/**
 * @author litb
 * @date 2022/5/21 15:48
 * <p>
 * 自研文件服務實現(xiàn)
 */
public class CustomFileOperationServiceImpl implements IFileOperationService {

    @Override
    public String upload(FileUploadDto dto) {
        System.out.println("自研文件服務上傳文件...");
        return null;
    }

    @Override
    public String upload4Stream(FileUploadForStreamDto streamDto) {
        System.out.println("自研文件服務流式上傳文件...");
        return null;
    }

    @Override
    public FileDownloadDto download(String fileId) {
        System.out.println("自研文件服務下載文件...");
        return null;
    }

    @Override
    public FileDownloadForStreamDto download4Stream(String fileId) {
        System.out.println("自研文件服務流式下載文件...");
        return null;
    }
}

第三方文件服務:

package com.cube.dp.adapter.fs.third;

import com.cube.dp.adapter.fs.third.dto.FileDownloadDto;
import com.cube.dp.adapter.fs.third.dto.FileDownloadForStreamDto;
import com.cube.dp.adapter.fs.third.dto.FileUploadDto;
import com.cube.dp.adapter.fs.third.dto.FileUploadForStreamDto;

/**
 * @author litb
 * @date 2022/5/21 15:32
 * <p>
 * 第三方文件服務接口
 */
public interface IThirdPartyFileOperationService {


    /**
     * 上傳文件
     *
     * @param dto 參數(shù)
     * @return 文件id
     */
    String upload(FileUploadDto dto);

    /**
     * 流式上傳文件
     *
     * @param streamDto 參數(shù)
     * @return 文件id
     */
    String upload4Stream(FileUploadForStreamDto streamDto);

    /**
     * 下載文件
     *
     * @param fileId 文件id
     * @return 結(jié)果
     */
    FileDownloadDto download(String fileId);

    /**
     * 流式下載文件
     *
     * @param fileId 文件id
     * @return 結(jié)果
     */
    FileDownloadForStreamDto download4Stream(String fileId);
}

oss文件服務實現(xiàn)

package com.cube.dp.adapter.fs.third;

import com.cube.dp.adapter.fs.third.dto.FileDownloadDto;
import com.cube.dp.adapter.fs.third.dto.FileDownloadForStreamDto;
import com.cube.dp.adapter.fs.third.dto.FileUploadDto;
import com.cube.dp.adapter.fs.third.dto.FileUploadForStreamDto;

/**
 * @author litb
 * @date 2022/5/21 15:48
 * <p>
 * 自研文件服務實現(xiàn)
 */
public class OssFileOperationServiceImpl implements IThirdPartyFileOperationService {

    @Override
    public String upload(FileUploadDto dto) {
        System.out.println("oss文件服務上傳文件...");
        return null;
    }

    @Override
    public String upload4Stream(FileUploadForStreamDto streamDto) {
        System.out.println("oss文件服務流式上傳文件...");
        return null;
    }

    @Override
    public FileDownloadDto download(String fileId) {
        System.out.println("oss文件服務下載文件...");
        return null;
    }

    @Override
    public FileDownloadForStreamDto download4Stream(String fileId) {
        System.out.println("oss文件服務流式下載文件...");
        return null;
    }
}

看一下兩者的目錄結(jié)構(gòu):


image.png

這里保證了自研文件服務和第三方文件服務的類名盔憨、接口完全一致,原因上面已經(jīng)說過了讯沈。
這里因為是為了方便演示放在同一個項目下所以兩者的包路徑差別不大郁岩,實際上兩者的包路徑可以說是沒有任何相似之處。

再復述一下我們在雙寫階段的目標:文件雙寫+對外暴露第三方文件服務定義的接口和方法
缺狠,提供如下適配器

package com.cube.dp.adapter;


import com.cube.dp.adapter.fs.third.IThirdPartyFileOperationService;
import com.cube.dp.adapter.fs.third.dto.FileDownloadDto;
import com.cube.dp.adapter.fs.third.dto.FileDownloadForStreamDto;
import com.cube.dp.adapter.fs.third.dto.FileUploadDto;
import com.cube.dp.adapter.fs.third.dto.FileUploadForStreamDto;

/**
 * @author litb
 * @date 2022/5/21 15:28
 * <p>
 * 文件操作適配器
 * 將自研文件服務與第三方文件服務適配
 */
public interface FileOperationAdaptee extends IThirdPartyFileOperationService {

    /**
     * 轉(zhuǎn)換
     *
     * @param dto 參數(shù)
     * @return 結(jié)果
     */
    default com.cube.dp.adapter.fs.custom.dto.FileUploadDto to(FileUploadDto dto) {
        if (dto == null) {
            return null;
        }
        com.cube.dp.adapter.fs.custom.dto.FileUploadDto fileUploadDto = new com.cube.dp.adapter.fs.custom.dto.FileUploadDto();

        fileUploadDto.setFileName(dto.getFileName());
        fileUploadDto.setFileContent(dto.getFileContent());
        fileUploadDto.setContentType(dto.getContentType());
        fileUploadDto.setMetadata(dto.getMetadata());

        return fileUploadDto;
    }

    /**
     * 轉(zhuǎn)換
     *
     * @param dto 參數(shù)
     * @return 結(jié)果
     */
    default com.cube.dp.adapter.fs.custom.dto.FileUploadForStreamDto to(FileUploadForStreamDto dto) {
        if (dto == null) {
            return null;
        }
        com.cube.dp.adapter.fs.custom.dto.FileUploadForStreamDto fileUploadDto = new com.cube.dp.adapter.fs.custom.dto.FileUploadForStreamDto();

        fileUploadDto.setFileName(dto.getFileName());
        //輸入流一般是不能重復讀取的,實際上應該采用byte數(shù)組拷貝或者轉(zhuǎn)換成可重復讀去的輸入流,本案例只是為了演示適配器模式的用法,不嚴格考慮具體的實現(xiàn)細節(jié)了
        fileUploadDto.setFileContent(dto.getFileContent());
        fileUploadDto.setContentType(dto.getContentType());
        fileUploadDto.setMetadata(dto.getMetadata());

        return fileUploadDto;
    }


    /**
     * 轉(zhuǎn)換
     *
     * @param dto 參數(shù)
     * @return 結(jié)果
     */
    default com.cube.dp.adapter.fs.custom.dto.FileDownloadDto to(FileDownloadDto dto) {
        if (dto == null) {
            return null;
        }
        com.cube.dp.adapter.fs.custom.dto.FileDownloadDto fileUploadDto = new com.cube.dp.adapter.fs.custom.dto.FileDownloadDto();

        fileUploadDto.setFileName(dto.getFileName());
        fileUploadDto.setFileContent(dto.getFileContent());
        fileUploadDto.setContentType(dto.getContentType());
        fileUploadDto.setMetadata(dto.getMetadata());

        return fileUploadDto;
    }

    /**
     * 轉(zhuǎn)換
     *
     * @param dto 參數(shù)
     * @return 結(jié)果
     */
    default FileDownloadDto to(com.cube.dp.adapter.fs.custom.dto.FileDownloadDto dto) {
        if (dto == null) {
            return null;
        }
        FileDownloadDto fileUploadDto = new FileDownloadDto();

        fileUploadDto.setFileName(dto.getFileName());
        fileUploadDto.setFileContent(dto.getFileContent());
        fileUploadDto.setContentType(dto.getContentType());
        fileUploadDto.setMetadata(dto.getMetadata());

        return fileUploadDto;
    }

    /**
     * 轉(zhuǎn)換
     *
     * @param dto 參數(shù)
     * @return 結(jié)果
     */
    default com.cube.dp.adapter.fs.custom.dto.FileDownloadForStreamDto to(FileDownloadForStreamDto dto) {
        if (dto == null) {
            return null;
        }
        com.cube.dp.adapter.fs.custom.dto.FileDownloadForStreamDto fileUploadDto = new com.cube.dp.adapter.fs.custom.dto.FileDownloadForStreamDto();

        fileUploadDto.setFileName(dto.getFileName());
        //輸入流一般是不能重復讀取的,實際上應該采用byte數(shù)組拷貝或者轉(zhuǎn)換成可重復讀去的輸入流,本案例只是為了演示適配器模式的用法,不嚴格考慮具體的實現(xiàn)細節(jié)了
        fileUploadDto.setFileContent(dto.getFileContent());
        fileUploadDto.setContentType(dto.getContentType());
        fileUploadDto.setMetadata(dto.getMetadata());

        return fileUploadDto;
    }

    /**
     * 轉(zhuǎn)換
     *
     * @param dto 參數(shù)
     * @return 結(jié)果
     */
    default FileDownloadForStreamDto to(com.cube.dp.adapter.fs.custom.dto.FileDownloadForStreamDto dto) {
        if (dto == null) {
            return null;
        }
        FileDownloadForStreamDto fileUploadDto = new FileDownloadForStreamDto();

        fileUploadDto.setFileName(dto.getFileName());
        //輸入流一般是不能重復讀取的,實際上應該采用byte數(shù)組拷貝或者轉(zhuǎn)換成可重復讀去的輸入流,本案例只是為了演示適配器模式的用法,不嚴格考慮具體的實現(xiàn)細節(jié)了
        fileUploadDto.setFileContent(dto.getFileContent());
        fileUploadDto.setContentType(dto.getContentType());
        fileUploadDto.setMetadata(dto.getMetadata());

        return fileUploadDto;
    }

}

該適配器首先繼承了第三方文件服務的定義的接口IThirdPartyFileOperationService问慎,提供了一些將新舊文件服務參數(shù)相互轉(zhuǎn)換的默認方法。
再提供一個抽象的雙寫適配器

package com.cube.dp.adapter;

import com.cube.dp.adapter.fs.custom.IFileOperationService;
import com.cube.dp.adapter.fs.third.IThirdPartyFileOperationService;
import com.cube.dp.adapter.fs.third.dto.FileUploadDto;
import com.cube.dp.adapter.fs.third.dto.FileUploadForStreamDto;

/**
 * @author litb
 * @date 2022/5/21 16:52
 * <p>
 * 抽象文件雙寫適配器,文件上傳時,會先將文件上傳只自研文件服務實現(xiàn),然后再將該文件上傳至第三方文件服務實現(xiàn),
 * 同一個文件上傳后在自研文件服務和第三方文件服務內(nèi)的文件id是一致的
 */
public abstract class AbstractFileDoubleWriteOperationAdaptor implements FileOperationAdaptee {

    private final IFileOperationService fileOperationService;

    private final IThirdPartyFileOperationService thirdPartyFileOperationService;

    public AbstractFileDoubleWriteOperationAdaptor(IFileOperationService fileOperationService,
                                                   IThirdPartyFileOperationService thirdPartyFileOperationService) {
        this.fileOperationService = fileOperationService;
        this.thirdPartyFileOperationService = thirdPartyFileOperationService;
    }

    @Override
    public String upload(FileUploadDto dto) {
        String fileId = fileOperationService.upload(to(dto));
        //使用上傳至自研文件服務的文件id作為第三方文件服務上傳文件時的key,這樣就能夠報證同一個文件在兩個文件服務的文件id是一致的,這個邏輯這里就不寫了
        return thirdPartyFileOperationService.upload(dto);
    }

    @Override
    public String upload4Stream(FileUploadForStreamDto streamDto) {
        String fileId = fileOperationService.upload4Stream(to(streamDto));
        //使用上傳至自研文件服務的文件id作為第三方文件服務上傳文件時的key,這樣就能夠報證同一個文件在兩個文件服務的文件id是一致的,這個邏輯這里就不寫了
        return thirdPartyFileOperationService.upload4Stream(streamDto);
    }

    public IFileOperationService getFileOperationService() {
        return fileOperationService;
    }

    public IThirdPartyFileOperationService getThirdPartyFileOperationService() {
        return thirdPartyFileOperationService;
    }
}

再提供一個文件上傳時雙寫且從自研文件服務中讀取文件的適配器

package com.cube.dp.adapter;

import com.cube.dp.adapter.fs.custom.IFileOperationService;
import com.cube.dp.adapter.fs.third.IThirdPartyFileOperationService;
import com.cube.dp.adapter.fs.third.dto.FileDownloadDto;
import com.cube.dp.adapter.fs.third.dto.FileDownloadForStreamDto;

/**
 * @author litb
 * @date 2022/5/21 17:08
 * <p>
 * 上傳時雙寫,讀取時從自研文件服務中讀取的適配器
 */
public class DoubleWriteAndReadCustomOperationAdaptor extends AbstractFileDoubleWriteOperationAdaptor {

    public DoubleWriteAndReadCustomOperationAdaptor(IFileOperationService fileOperationService,
                                                    IThirdPartyFileOperationService thirdPartyFileOperationService) {
        super(fileOperationService, thirdPartyFileOperationService);
    }

    @Override
    public FileDownloadDto download(String fileId) {
        return to(getFileOperationService().download(fileId));
    }

    @Override
    public FileDownloadForStreamDto download4Stream(String fileId) {
        return to(getFileOperationService().download4Stream(fileId));
    }
}

這里不提供抽象的文件雙寫適配器AbstractFileDoubleWriteOperationAdaptor直接在DoubleWriteAndReadCustomOperationAdaptor實現(xiàn)雙寫邏輯也是可以的(因為實際上只能從自研文件服務中讀取儒老,這樣才能確保增量數(shù)據(jù)和存量數(shù)據(jù)都能讀取成功)

再提供一個獲取文件服務的工廠

package com.cube.dp.adapter;

import com.cube.dp.adapter.fs.custom.CustomFileOperationServiceImpl;
import com.cube.dp.adapter.fs.third.IThirdPartyFileOperationService;
import com.cube.dp.adapter.fs.third.OssFileOperationServiceImpl;

/**
 * @author litb
 * @date 2022/5/21 17:12
 * <p>
 * 文件服務工廠
 */
public class FileOperationFactory {


    public static IThirdPartyFileOperationService getDefault() {
        return getInstance(EnumFileOperationType.DOUBLE_WRITE_AND_READ_FROM_CUSTOM);
    }

    /**
     * 獲取對應的文件服務實例
     *
     * @param operationType 類型
     * @return 實例
     */
    public static IThirdPartyFileOperationService getInstance(EnumFileOperationType operationType) {
        switch (operationType) {
            case OSS:
                return new OssFileOperationServiceImpl();
            case CUSTOM:
                return new CustomFileOperationAdaptor(new CustomFileOperationServiceImpl());
            case DOUBLE_WRITE_AND_READ_FROM_CUSTOM:
                return new DoubleWriteAndReadCustomOperationAdaptor(new CustomFileOperationServiceImpl(),
                        new OssFileOperationServiceImpl());
            default:
                throw new IllegalArgumentException("storageType is not support");
        }
    }
}

各個依賴方可以通過getDefault方法獲取默認的文件服務實例蝴乔,在雙寫階段提供的是上傳時雙寫+從自研文件服務中讀取的實現(xiàn)记餐,在第二階段存量文件同步完成后升級一下第三方文件服務的版本完全移除自研文件服務的依賴并默認提供第三方文件服務實例即可驮樊,各個依賴方引入新的版本重新發(fā)布一下項目即可,改動程度相對較小。

假設有以下客戶端依賴了文件服務:
一囚衔、文件雙寫+存量數(shù)據(jù)同步階段

package com.cube.dp.adapter;

import com.cube.dp.adapter.fs.third.IThirdPartyFileOperationService;
import com.cube.dp.adapter.fs.third.dto.FileUploadDto;

/**
 * @author litb
 * @date 2022/5/21 17:16
 * <p>
 * 假裝這是一個項目
 */
public class ProjectClient {

    public static void main(String[] args) {
        IThirdPartyFileOperationService operationService =
                FileOperationFactory.getInstance(EnumFileOperationType.DOUBLE_WRITE_AND_READ_FROM_CUSTOM);
        operationService.upload(new FileUploadDto());

        operationService.download("this is fileId");
    }
}

模擬下文件上傳及下載挖腰,控制臺輸出如下:

自研文件服務上傳文件...
oss文件服務上傳文件...
自研文件服務下載文件...

可以看出,上傳時是雙寫练湿,讀取時是從自研文件服務中讀取猴仑。

二、存量數(shù)據(jù)同步完成之后
在存量數(shù)據(jù)同步完成之后肥哎,這個時候自研文件服務和oss中的存量數(shù)據(jù)和增量數(shù)據(jù)都是完全一致的辽俗,可以無縫切換到oss文件服務了,完全移除自研文件服務篡诽。

package com.cube.dp.adapter;

import com.cube.dp.adapter.fs.third.IThirdPartyFileOperationService;
import com.cube.dp.adapter.fs.third.dto.FileUploadDto;

/**
 * @author litb
 * @date 2022/5/21 17:16
 * <p>
 * 假裝這是一個項目
 */
public class ProjectClient {

    public static void main(String[] args) {
        IThirdPartyFileOperationService operationService =
                //切換到oss實現(xiàn),這一步在文件服務工程下完成即可,切換實現(xiàn)并完全移除自研文件服務后升級打包讓各個依賴方重新引入
                FileOperationFactory.getInstance(EnumFileOperationType.OSS);
        operationService.upload(new FileUploadDto());

        operationService.download("this is fileId");
    }
}

模擬下文件上傳和下載崖飘,控制臺輸出如下:

oss文件服務上傳文件...
oss文件服務下載文件...

而且,考慮到不可控因素杈女,還提供了基于第三方文件服務接口定義但是由自研文件服務提供實現(xiàn)的適配器

package com.cube.dp.adapter;

import com.cube.dp.adapter.fs.custom.IFileOperationService;
import com.cube.dp.adapter.fs.third.dto.FileDownloadDto;
import com.cube.dp.adapter.fs.third.dto.FileDownloadForStreamDto;
import com.cube.dp.adapter.fs.third.dto.FileUploadDto;
import com.cube.dp.adapter.fs.third.dto.FileUploadForStreamDto;

/**
 * @author litb
 * @date 2022/5/21 16:23
 * <p>
 * 文件適配器,將第三方文件服務與自研文件服務適配
 */
public class CustomFileOperationAdaptor implements FileOperationAdaptee {

    private final IFileOperationService customFileOperationService;

    public CustomFileOperationAdaptor(IFileOperationService customFileOperationService) {
        this.customFileOperationService = customFileOperationService;
    }

    @Override
    public String upload(FileUploadDto dto) {
        return customFileOperationService.upload(to(dto));
    }

    @Override
    public String upload4Stream(FileUploadForStreamDto streamDto) {
        return customFileOperationService.upload4Stream(to(streamDto));
    }

    @Override
    public FileDownloadDto download(String fileId) {
        return to(customFileOperationService.download(fileId));
    }

    @Override
    public FileDownloadForStreamDto download4Stream(String fileId) {
        return to(customFileOperationService.download4Stream(fileId));
    }
}

假設要突然完全切換到自研文件服務朱浴,在第三方文件服務項目中切換到自研文件重新升級打包即可,各個項目重新引入新版本即可达椰,無需回滾代碼(主要是包路徑調(diào)整)翰蠢。

上述適配器模式的類圖如下所示:


文件服務-適配器模式類圖.png

表達能力欠缺一直是我的諸多缺點之一,不知道我上面一頓啰嗦有沒有把我的想法表達清楚啰劲,參考代碼也許更易理解一點梁沧,附上鏈接:適配器模式代碼

總結(jié)

說一下為什么中途寫到適配器模式類型的定義時讓我覺得突然不想再寫了,就像倚天屠龍記里張三豐教張無忌太極拳和太極劍一樣蝇裤,張無忌看了一遍之后雖然全部都忘記了但是最后卻能夠嫻熟的運用出來趁尼,忘與不忘在我看來其中的差別其實就是無形有形的區(qū)別,有形只是生搬硬套猖辫,而無形卻是融會貫通酥泞;設計模式難學的主要原因就是人為的界定了許多界限,當我在看完適配器類型的定義之后我把我上面寫的代碼往這個定義去套啃憎,嘗試去解釋這里面的一些概念芝囤,但是最終我發(fā)現(xiàn)連我自己都難以說服,所以我決定不再糾結(jié)這些具體的概念和定義辛萍,只是把我的想法表達出來就行了悯姊。

最后,說一些我個人最近的一些感悟贩毕,我寫代碼的時間不算長悯许,最開始時寫代碼的時候,我覺得代碼是難以控制的辉阶,不確定在什么地方會出問題先壕,總是害怕出bug瘩扼;不知道是上個月啥時候開始,我突然覺得我是能夠控制住代碼的垃僚,能夠參照一部分源碼寫出一部分我覺得還不錯的代碼(起碼看起來還不錯)集绰,這應該還是處于有形的階段;但是谆棺,我覺得后面至少應該還有一個階段栽燕,當我寫出一段代碼后我會由衷的感嘆:這段代碼是這樣不是因為我想要這樣寫,而是這段代碼原本就應該是這個樣子改淑,就算是再讓我寫一千遍一萬遍碍岔,它也應該就是這個樣子。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末朵夏,一起剝皮案震驚了整個濱河市付秕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌侍郭,老刑警劉巖询吴,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異亮元,居然都是意外死亡猛计,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門爆捞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奉瘤,“玉大人,你說我怎么就攤上這事煮甥〉廖拢” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵成肘,是天一觀的道長卖局。 經(jīng)常有香客問我,道長双霍,這世上最難降的妖魔是什么砚偶? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮洒闸,結(jié)果婚禮上染坯,老公的妹妹穿的比我還像新娘。我一直安慰自己丘逸,他們只是感情好单鹿,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著深纲,像睡著了一般仲锄。 火紅的嫁衣襯著肌膚如雪劲妙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天昼窗,我揣著相機與錄音,去河邊找鬼涛舍。 笑死澄惊,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的富雅。 我是一名探鬼主播掸驱,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼没佑!你這毒婦竟也來了毕贼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤蛤奢,失蹤者是張志新(化名)和其女友劉穎鬼癣,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體啤贩,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡待秃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了痹屹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片章郁。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖志衍,靈堂內(nèi)的尸體忽然破棺而出暖庄,到底是詐尸還是另有隱情,我是刑警寧澤楼肪,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布培廓,位于F島的核電站,受9級特大地震影響春叫,放射性物質(zhì)發(fā)生泄漏医舆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一象缀、第九天 我趴在偏房一處隱蔽的房頂上張望蔬将。 院中可真熱鬧,春花似錦央星、人聲如沸霞怀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毙石。三九已至廉沮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間徐矩,已是汗流浹背滞时。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留滤灯,地道東北人坪稽。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像鳞骤,于是被迫代替她去往敵國和親窒百。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容