重學 Java 設計模式:實戰橋接模式(多支付渠道「微信、支付寶」與多支付模式「刷臉、指紋」場景)

作者:小傅哥
博客:https://bugstack.cn – 編寫系列原創專題文章

沉澱、分享、成長,讓自己和他人都能有所收穫!

一、前言

為什麼你的代碼那麼多ifelse

同類的業務、同樣的功能,怎麼就你能寫出來那麼多ifelse。很多時候一些剛剛從校園進入企業的萌新,或者一部分從小公司跳槽到大企業的程序員,初次承接業務需求的時候,往往編碼還不成熟,經常一桿到底的寫需求。初次實現確實很快,但是後期維護和擴展就十分痛苦。因為一段代碼的可讀性閱讀他後期的維護成本也就越高。

設計模式是可以幫助你改善代碼

很多時候你寫出來的ifelse都是沒有考慮使用設計模式優化,就像;同類服務的不同接口適配包裝、同類物料不同組合的建造、多種獎品組合的營銷工廠等等。它們都可以讓你代碼中原本使用if判斷的地方,變成一組組類和面向對象的實現過程。

怎麼把設計模式和實際開發結合起來

多從實際場景思考,只找到代碼優化的最佳點,不要可以想着設計模式的使用。就像你最開始看設計模式適合,因為沒有真實的場景模擬案例,都是一些畫圓形、方形,對新人或者理解能力還不到的夥伴來說很不友好。所以即使學了半天 ,但實際使用還是摸不着頭腦。

二、開發環境

  1. JDK 1.8
  2. Idea + Maven
  3. 涉及工程三個,可以通過關注公眾號bugstack蟲洞棧,回復源碼下載獲取(打開獲取的鏈接,找到序號18)
工程 描述
itstack-demo-design-7-01 使用一坨代碼實現業務需求
itstack-demo-design-7-02 通過設計模式優化改造代碼,產生對比性從而學習

三、橋接模式介紹

橋接模式的主要作用就是通過將抽象部分與實現部分分離,把多種可匹配的使用進行組合。說白了核心實現也就是在A類中含有B類接口,通過構造函數傳遞B類的實現,這個B類就是設計的

那麼這樣的橋接模式,在我們平常的開發中有哪些場景

JDBC多種驅動程序的實現、同品牌類型的台式機和筆記本平板、業務實現中的多類接口同組過濾服務等。這些場景都比較適合使用橋接模式進行實現,因為在一些組合中如果有如果每一個類都實現不同的服務可能會出現笛卡爾積,而使用橋接模式就可以非常簡單。

四、案例場景模擬

隨着市場的競爭在支付服務行業出現了微信和支付寶還包括一些其他支付服務,但是對於商家來說並不希望改變用戶習慣。就像如果我的地攤只能使用微信或者只能使用支付寶付款,那麼就會讓我顧客傷心,雞蛋灌餅也賣不動了。

在這個時候就出現了第三方平台,把市面上綜合佔據市場90%以上的支付服務都集中到自己平台中,再把這樣的平台提供給店鋪、超市、地攤使用,同時支持人臉、掃描、密碼多種方式。

我們這個案例就模擬一個這樣的第三方平台來承接各個支付能力,同時使用自家的人臉讓用戶支付起來更加容易。那麼這裏就出現了多支付多模式的融合使用,如果給每一個支付都實現一次不同的模式,即使是繼承類也需要開發好多。而且隨着後面接入了更多的支付服務或者支付方式,就會呈爆炸似的擴展。

所以你現在可以思考一下這樣的場景該如何實現?

五、用一坨坨代碼實現

產品經理說老闆要的需求,要儘快上,kpi你看着弄!

既然你逼我那就別怪我無情,還沒有我一個類寫不完的需求!反正寫完就完事了,拿完績效也要走了天天逼着寫需求,代碼越來越亂心疼後面的兄弟3秒。

1. 工程結構

itstack-demo-design-7-01
└── src
    └── main
        └── java
            └── org.itstack.demo.design
                └── PayController.java
  • 只有一個類裏面都是ifelse,這個類實現了支付和模式的全部功能。

2. 代碼實現

public class PayController {

    private Logger logger = LoggerFactory.getLogger(PayController.class);

    public boolean doPay(String uId, String tradeId, BigDecimal amount, int channelType, int modeType) {
        // 微信支付
        if (1 == channelType) {
            logger.info("模擬微信渠道支付划賬開始。uId:{} tradeId:{} amount:{}", uId, tradeId, amount);
            if (1 == modeType) {
                logger.info("密碼支付,風控校驗環境安全");
            } else if (2 == modeType) {
                logger.info("人臉支付,風控校驗臉部識別");
            } else if (3 == modeType) {
                logger.info("指紋支付,風控校驗指紋信息");
            }
        }
        // 支付寶支付
        else if (2 == channelType) {
            logger.info("模擬支付寶渠道支付划賬開始。uId:{} tradeId:{} amount:{}", uId, tradeId, amount);
            if (1 == modeType) {
                logger.info("密碼支付,風控校驗環境安全");
            } else if (2 == modeType) {
                logger.info("人臉支付,風控校驗臉部識別");
            } else if (3 == modeType) {
                logger.info("指紋支付,風控校驗指紋信息");
            }
        }
        return true;
    }

}
  • 上面的類提供了一個支付服務功能,通過提供的必要字段;用戶ID交易ID金額渠道模式,來控制支付方式。
  • 以上的ifelse應該是最差的一種寫法,即使寫ifelse也是可以優化的方式去寫的。

3. 測試驗證

3.1 編寫測試類

@Test
public void test_pay() {
    PayController pay = new PayController();
    System.out.println("\r\n模擬測試場景;微信支付、人臉方式。");
    pay.doPay("weixin_1092033111", "100000109893", new BigDecimal(100), 1, 2);
    
    System.out.println("\r\n模擬測試場景;支付寶支付、指紋方式。");
    pay.doPay("jlu19dlxo111","100000109894",new BigDecimal(100), 2, 3);
}
  • 以上分別測試了兩種不同的支付類型和支付模式;微信人臉支付、支付寶指紋支付

3.2 測試結果

模擬測試場景;微信支付、人臉方式。
23:05:59.152 [main] INFO  o.i.demo.design.pay.channel.Pay - 模擬微信渠道支付划賬開始。uId:weixin_1092033111 tradeId:100000109893 amount:100
23:05:59.155 [main] INFO  o.i.demo.design.pay.mode.PayCypher - 人臉支付,風控校驗臉部識別
23:05:59.155 [main] INFO  o.i.demo.design.pay.channel.Pay - 模擬微信渠道支付風控校驗。uId:weixin_1092033111 tradeId:100000109893 security:true
23:05:59.155 [main] INFO  o.i.demo.design.pay.channel.Pay - 模擬微信渠道支付划賬成功。uId:weixin_1092033111 tradeId:100000109893 amount:100

模擬測試場景;支付寶支付、指紋方式。
23:05:59.156 [main] INFO  o.i.demo.design.pay.channel.Pay - 模擬支付寶渠道支付划賬開始。uId:jlu19dlxo111 tradeId:100000109894 amount:100
23:05:59.156 [main] INFO  o.i.demo.design.pay.mode.PayCypher - 指紋支付,風控校驗指紋信息
23:05:59.156 [main] INFO  o.i.demo.design.pay.channel.Pay - 模擬支付寶渠道支付風控校驗。uId:jlu19dlxo111 tradeId:100000109894 security:true
23:05:59.156 [main] INFO  o.i.demo.design.pay.channel.Pay - 模擬支付寶渠道支付划賬成功。uId:jlu19dlxo111 tradeId:100000109894 amount:100

Process finished with exit code 0
  • 從測試結果看已經滿足了我們的不同支付類型和支付模式的組合,但是這樣的代碼在後面的維護以及擴展都會變得非常複雜。

六、橋接模式重構代碼

接下來使用橋接模式來進行代碼優化,也算是一次很小的重構。

從上面的ifelse方式實現來看,這是兩種不同類型的相互組合。那麼就可以把支付方式支付模式進行分離通過抽象類依賴實現類的方式進行橋接,通過這樣的拆分后支付與模式其實是可以單獨使用的,當需要組合時候只需要把模式傳遞給支付即可。

橋接模式的關鍵是選擇的橋接點拆分,是否可以找到這樣類似的相互組合,如果沒有就不必要非得使用橋接模式。

1. 工程結構

itstack-demo-design-7-02
└── src
    ├── main
    │   └── java
    │       └── org.itstack.demo.design.pay
    │           ├── channel
    │           │   ├── Pay.java
    │           │   ├── WxPay.java
    │           │   └── ZfbPay.java
    │           └── mode
    │               ├── IPayMode.java
    │               ├── PayCypher.java
    │               ├── PayFaceMode.java
    │               └── PayFingerprintMode.java
    └── test
         └── java
             └── org.itstack.demo.design.test
                 └── ApiTest.java

橋接模式模型結構

  • 左側Pay是一個抽象類,往下是它的兩個支付類型實現;微信支付、支付寶支付。
  • 右側IPayMode是一個接口,往下是它的兩個支付模型;刷臉支付、指紋支付。
  • 那麼,支付類型 × 支付模型 = 就可以得到相應的組合。

2. 代碼實現

2.1 支付類型橋接抽象類

public abstract class Pay {

    protected Logger logger = LoggerFactory.getLogger(Pay.class);

    protected IPayMode payMode;

    public Pay(IPayMode payMode) {
        this.payMode = payMode;
    }

    public abstract String transfer(String uId, String tradeId, BigDecimal amount);

}
  • 在這個類中定義了支付方式的需要實現的划賬接口:transfer,以及橋接接口;IPayMode,並在構造函數中用戶方自行選擇支付方式。
  • 如果沒有接觸過此類實現,可以重點關注 IPayMode payMode,這部分是橋接的核心。

2.2 兩個支付類型的實現

微信支付

public class WxPay extends Pay {

    public WxPay(IPayMode payMode) {
        super(payMode);
    }

    public String transfer(String uId, String tradeId, BigDecimal amount) {
        logger.info("模擬微信渠道支付划賬開始。uId:{} tradeId:{} amount:{}", uId, tradeId, amount);
        boolean security = payMode.security(uId);
        logger.info("模擬微信渠道支付風控校驗。uId:{} tradeId:{} security:{}", uId, tradeId, security);
        if (!security) {
            logger.info("模擬微信渠道支付划賬攔截。uId:{} tradeId:{} amount:{}", uId, tradeId, amount);
            return "0001";
        }
        logger.info("模擬微信渠道支付划賬成功。uId:{} tradeId:{} amount:{}", uId, tradeId, amount);
        return "0000";
    }

}

支付寶支付

public class ZfbPay extends Pay {

    public ZfbPay(IPayMode payMode) {
        super(payMode);
    }

    public String transfer(String uId, String tradeId, BigDecimal amount) {
        logger.info("模擬支付寶渠道支付划賬開始。uId:{} tradeId:{} amount:{}", uId, tradeId, amount);
        boolean security = payMode.security(uId);
        logger.info("模擬支付寶渠道支付風控校驗。uId:{} tradeId:{} security:{}", uId, tradeId, security);
        if (!security) {
            logger.info("模擬支付寶渠道支付划賬攔截。uId:{} tradeId:{} amount:{}", uId, tradeId, amount);
            return "0001";
        }
        logger.info("模擬支付寶渠道支付划賬成功。uId:{} tradeId:{} amount:{}", uId, tradeId, amount);
        return "0000";
    }

}
  • 這裏分別模擬了調用第三方的兩個支付渠道;微信、支付寶,當然作為支付綜合平台可能不只是接了這兩個渠道,還會有其很跟多渠道。
  • 另外可以看到在支付的時候分別都調用了風控的接口進行驗證,也就是不同模式的支付(刷臉指紋),都需要過指定的風控,才能保證支付安全。

2.3 定義支付模式接口

public interface IPayMode {

    boolean security(String uId);

}
  • 任何一個支付模式;刷臉、指紋、密碼,都會過不同程度的安全風控,這裏定義一個安全校驗接口。

2.4 三種支付模式風控(刷臉、指紋、密碼)

刷臉

public class PayFaceMode implements IPayMode{

    protected Logger logger = LoggerFactory.getLogger(PayCypher.class);

    public boolean security(String uId) {
        logger.info("人臉支付,風控校驗臉部識別");
        return true;
    }

}

指紋

public class PayFingerprintMode implements IPayMode{

    protected Logger logger = LoggerFactory.getLogger(PayCypher.class);

    public boolean security(String uId) {
        logger.info("指紋支付,風控校驗指紋信息");
        return true;
    }

}

密碼

public class PayCypher implements IPayMode{

    protected Logger logger = LoggerFactory.getLogger(PayCypher.class);

    public boolean security(String uId) {
        logger.info("密碼支付,風控校驗環境安全");
        return true;
    }

}
  • 在這裏實現了三種支付模式(刷臉、指紋、密碼)的風控校驗,在用戶選擇不同支付類型的時候,則會進行相應的風控攔截以此保障支付安全。

3. 測試驗證

3.1 編寫測試類

@Test
public void test_pay() {
    System.out.println("\r\n模擬測試場景;微信支付、人臉方式。");
    Pay wxPay = new WxPay(new PayFaceMode());
    wxPay.transfer("weixin_1092033111", "100000109893", new BigDecimal(100));

    System.out.println("\r\n模擬測試場景;支付寶支付、指紋方式。");
    Pay zfbPay = new ZfbPay(new PayFingerprintMode());
    zfbPay.transfer("jlu19dlxo111","100000109894",new BigDecimal(100));
}
  • 與上面的ifelse實現方式相比,這裏的調用方式變得整潔、乾淨、易使用;new WxPay(new PayFaceMode())new ZfbPay(new PayFingerprintMode())
  • 外部的使用接口的用戶不需要關心具體的實現,只按需選擇使用即可。

3.2 測試結果

模擬測試場景;微信支付、人臉方式。
23:14:40.911 [main] INFO  o.i.demo.design.pay.channel.Pay - 模擬微信渠道支付划賬開始。uId:weixin_1092033111 tradeId:100000109893 amount:100
23:14:40.914 [main] INFO  o.i.demo.design.pay.mode.PayCypher - 人臉支付,風控校驗臉部識別
23:14:40.914 [main] INFO  o.i.demo.design.pay.channel.Pay - 模擬微信渠道支付風控校驗。uId:weixin_1092033111 tradeId:100000109893 security:true
23:14:40.915 [main] INFO  o.i.demo.design.pay.channel.Pay - 模擬微信渠道支付划賬成功。uId:weixin_1092033111 tradeId:100000109893 amount:100

模擬測試場景;支付寶支付、指紋方式。
23:14:40.915 [main] INFO  o.i.demo.design.pay.channel.Pay - 模擬支付寶渠道支付划賬開始。uId:jlu19dlxo111 tradeId:100000109894 amount:100
23:14:40.915 [main] INFO  o.i.demo.design.pay.mode.PayCypher - 指紋支付,風控校驗指紋信息
23:14:40.915 [main] INFO  o.i.demo.design.pay.channel.Pay - 模擬支付寶渠道支付風控校驗。uId:jlu19dlxo111 tradeId:100000109894 security:true
23:14:40.915 [main] INFO  o.i.demo.design.pay.channel.Pay - 模擬支付寶渠道支付划賬成功。uId:jlu19dlxo111 tradeId:100000109894 amount:100

Process finished with exit code 0
  • 從測試結果看內容是一樣的,但是整體的實現方式有了很大的變化。所以有時候不能只看結果,也要看看過程

七、總結

  • 通過模擬微信與支付寶兩個支付渠道在不同的支付模式下,刷臉指紋密碼,的組合從而體現了橋接模式的在這類場景中的合理運用。簡化了代碼的開發,給後續的需求迭代增加了很好的擴展性。
  • 從橋接模式的實現形式來看滿足了單一職責和開閉原則,讓每一部分內容都很清晰易於維護和拓展,但如果我們是實現的高內聚的代碼,那麼就會很複雜。所以在選擇重構代碼的時候,需要考慮好整體的設計,否則選不到合理的設計模式,將會讓代碼變得難以開發。
  • 任何一種設計模式的選擇和使用都應該遵頊符合場景為主,不要刻意使用。而且統一場景因為業務的複雜從而可能需要使用到多種設計模式的組合,才能將代碼設計的更加合理。但這種經驗需要從實際的項目中學習經驗,並提不斷的運用。

八、推薦閱讀

  • 1. 重學 Java 設計模式:實戰工廠方法模式(多種類型商品發獎場景)
  • 2. 重學 Java 設計模式:實戰抽象工廠模式(替換Redis雙集群升級場景)
  • 3. 重學 Java 設計模式:實戰建造者模式(裝修物料組合套餐選配場景)
  • 4. 重學 Java 設計模式:實戰原型模式(多套試每人題目和答案亂序場景)
  • 5. 重學 Java 設計模式:實戰單例模式(Effective Java 作者推薦枚舉單例模式)

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

.Net Core 會逆襲成為最受歡迎開發平台嗎?

本文由葡萄城技術團隊於博客園原創並首發

轉載請註明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。

.Net Core 是什麼?

最新.Net Core 熱詞霸佔了各個技術熱搜,看來微軟近年來發布的 .Net Core 還是成功了引起了大家的熱烈討論。如果您對微軟熟悉,肯定是很了解.Net 平台,但是隨着互聯網的興起,好像微軟這個霸主的地位有所撼動。

 

.NET Core 是.NET Framework的新一代版本,是微軟開發的第一個跨平台 (Windows、Mac OSX、Linux) 的應用程序開發框架(Application Framework),未來也將會支持 FreeBSD 與 Alpine 平台。.Net Core也是微軟在一開始發展時就開源的軟件平台[1],由於 .NET Core 的開發目標是跨平台的因此 .NET Core 會包含 .NET Framework 的類別庫,但與 .NET Framework 不同的是 .NET Core 採用包化 (Packages) 的管理方式,應用程序只需要獲取需要的組件即可,與 .NET Framework 大包式安裝的作法截然不同,同時各包亦有獨立的版本線 (Version line),不再硬性要求應用程序跟隨主線版本。

 

重點來啦:

  • 跨平台:可在 Windows、macOS 和 Linux 操作系統上運行
  • 跨體繫結構保持一致:在多個體繫結構(包括 x64、x86 和 ARM)上以相同的行為運行代碼
  • 命令行工具:包括可用於本地開發和持續集成方案中的易於使用的命令行工具。
  • 部署靈活:可以包含在應用或已安裝的并行(用戶或系統範圍安裝)中。 可搭配 Docker 容器使用
  • 兼容性: .NET Core 通過 .NET Standard 與 .NET Framework、Xamarin 和 Mono 兼容
  • 開放源代碼: .NET Core 平台是開放源代碼,使用 MIT 和 Apache 2 許可證。 .NET Core 是一個 .NET Foundation 項目
  • 強勁性能:超強的後台性能,超出.Net Framework
  • 支持命令行執行所有操作

 

.Net Core 當前的現狀是什麼

目前可以看到很多傳統行業的信息系統也在逐漸升級平台,而且很多大的互聯網公司也已經使用,畢竟一次開發即可實現跨平台的部署及應用,也是減少成本的重要體現。

 

可以確定.Net Core 是未來的發展趨勢。 .Net FrameWork也會延續使用,畢竟短期內遷移一些大型項目是很有難度的,而且也不太可能。.Net Core 和.Net FrameWork 的關係就如同是新能源汽車和傳統穩定的油耗汽車。油耗汽車已經經歷了多年的發展,技術非常成熟穩定,可以放心自由的使用。而新能源汽車是一個新興的技術,也是未來將要取待傳統技術的未來發展方向,所以使用.Net Core 開發項目必須越早越好。

 

.Net Core 與. Net FrameWork 對比:

.NET Core

.NET Framework

跨平台 (OS platform): 支持Windows, Linux, 及 macOS

僅支持在 Windows運行

安裝過程是獨立,端對端,可以在同一計算器中為應用程序指定獨立的.Net Core 版本。

一台計算機上的所有應用程序都在同一.NET Framework版本上運行

高性能:在集合,數學,正則表達式,字符串,文件等方面都有提升。.

高兼容性

開源: 基於.NET平台既可以根據 MIT或 Apache 2 授權

與最廣泛的NuGet軟件包,第三方庫和內部庫兼容

v2.0 實現了.NET Standard 2.0¹

v4.6.1+ 以上版本支持s .NET Standard 2.0

 

使用.Net Core 優勢:

1. 支持在任何平台部署,跨平台幾乎沒有任何成本

2. 龐大的.Net 標準庫支持

3. 面向高性能的服務器開發,基於 微軟 Azure雲的平台優勢,已提供高性能的服務。

4. 高性能和可移植性

5. 兼容多平台

 

如何平滑的遷移項目至.Net Core 平台

很多原有的項目是基於.Net FrameWork 開發的,可能是 Windows. WPF, ASP.NET MVC,那本身的局限是只能在Windows系統部署外,還涉及到一些核心功能的實現。傳統框架的種種不足,需要大的突破和改變。這意味着打破變化,但結果是值得期待的。

 

遷移原有項目到新的.Net Core 平台意味着你可以保留舊項目的所有核心業務功能,不需要重構整個項目,從0開始開發。以下是我們根據經驗給出了幾類的應用的遷移難度。

項目類型

遷移難易程度

Web 應用: ASP.NET MVC

簡單

WebForm 應用

不建議遷移,因為.Net Core 支持 WebForm

Windows 應用 (Universal Framework)

不需要遷移

Windows 應用(基於Sliverlight)

簡單

WPF 及WinForms 桌面應用

複雜

控制台應用

簡單

 

1. 遷移還是重構

如果針對前端項目,遷移是最佳選擇,畢竟前端代碼均可復用,唯一要改動的就是後端代碼。儘管.Net Core 和.Net Frame Work 項目都是基於C# 語言做開發的,然而兩者是不同的運行機制。所以如果是後端很重的項目,還是建議重寫,這樣也會利用一些新技術的優勢。

 

2. NuGet 包

在遷移之前,需要確認引用的.Net 標準庫是否在.Net Core中支持或丟棄,如果不支持的話,就需要考慮如何用新的包代替或者當前功能的重構。

.Net 標準包是在.Net 4.6.1 和.Net Core 中都可使用的,所以只需要可以使用該技術升級舊的PCL。如果你添加了.Net 標準庫的引用,同樣也可以在.Net Core 項目中使用。

 

3. Html / JavaScript / CSS 復用

可以將這些文件直接複製到.NET Core解決方案中。 但是,請確保更改代碼中的文件路徑,例如CSS中的圖像路徑。 因為經典的ASP.NET / MVC模板使用“ / Content /”目錄,而.NET Core使用“ / css /”,“ / js /”,“ / lib /”等。對此沒有任何限制,它們只是約定而已 。

 

如何選擇.Net Core 的開發工具

在開發項目時候,新的平台和技術總是帶給你項目的一些新的重大突破功能,比如性能,比如核心功能提升,所以不僅我們的項目要一直跟隨升級,我們所選擇的開發工具,也要緊跟技術前沿,甚至要領先於我們的項目升級進度,為我們開發項目始終提供最有力的技術支持。

 

.NET Core是多平台應用程序的未來。 如我們所見,.NET Core提供了傳統框架不支持的強大的本機新功能。 另一方面,.NET Core並不完全支持所有現有的應用程序類型進行遷移,尤其是那些與Windows OS緊密集成的應用程序類型,因此必須仔細考慮並計劃這些挑戰。

 

所以我們在選擇新平台的同時,也需要考慮一些輔助開發的工具。以及這些工具在該領域的技術背景,是否足夠穩定,是否有足夠明確的未來,甚至比我們更能預先跟蹤未來的技術棧,以始終在我們遷移新項目的時候提供輔助工具。

 

這裏推介一些支持.Net Core 平台的開發控件:

  • API Protability Tool。這是一款輔助.net開發者在不同的開發框架上遷移源代碼工程的靜態代碼審查工具。由於.net framework具有多個歷史版本,並且.net core以及Xamarin等開發框架在基礎類庫中實現API數量和類型有很多的不一致情況。.net開發者想把自身源代碼升級到更高的.net版本或者遷移到其他的.net開發框架上,會面臨很多API調用不兼容的問題。該工具就是幫助.net開發者審查.net項目的源代碼,並生成審查報告,快速幫助開發人員找到不兼容代碼行以及協助評估遷移工作量。
  • PostMan,Postman是一款支持跨平台的應用程序,用來幫助開發者快速構建和測試REST API 服務。Postman可以模擬HTTP請求的所有謂詞,用於REST API的測試。
  • Visual Studio Code , Visual Studio Code是跨操作系統平台的輕量級代碼編輯器。支持絕大多數主流語言編譯和調試的能力。
  • ActiveReports .Net 報表控件,專註報表領域20餘年,所以可見專業性以及對於.Net 技術的完善的集成技術,支持最新的ASP.Net Core MVC (.Net Core)項目的開發。可快速解決.Net Core 平台的報表設計,展示,打印/導出,數據鑽取等功能,與此也提供了最終用戶免費設計器(在線/桌面端)解決部署差異的難題。
  •  

     

  • Wyn Enterprise 嵌入式商業智能和報表軟件,基於.NET Core平台,可以以白標的方式嵌入到應用系統中,快速增強應用系統的自助式分析、移動BI、數據可視化、報表統計和數據填報等功能,最終用戶在業務系統中便能通過數據分析,為決策制定提供數據支撐。

  •  

     

     

 

綜上所述,無論從其性能和生態上預測,.NET Core 都極有可能成為最受歡迎的開發平台,不過,當前國內僅有騰訊、阿里等廠家願意試水,葡萄城作為一家具備30多年開發經驗的軟件廠商,同樣也在持續對.NET控件進行更新迭代。

如果您有 .NET Core及其衍生技術和開發工具的需求,請訪問葡萄城官網了解詳情。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

※回頭車貨運收費標準

MongoDB 4.X CRUD基本操作

本文總結了MongoDB 4.X在mongo shell客戶端涉及的對文檔一些基本的增刪改查操作,即CRUD操作。主要結合了自己平時使用MongoDB的操作命令,更詳細的命令可以參考官方文檔: https://docs.mongodb.com/manual/crud/

創建(Create Operations)

創建(Create Operations)也叫插入操作,當集合不存在時,插入操作同時也會創建集合。MongoDB提供以下幾種插入文檔方法:

  • db.collection.insert():在指定集合中插入單個或多個文檔。
  • db.collection.insertOne():在指定集合中插入單個文檔(版本3.2新增)。
  • db.collection.insertMany():在指定集合中插入多個文檔(版本3.2新增)。

db.collection.insert()

在平時的使用當中,db.collection.insert()是我用得最多的文檔插入方式,具體的語法格式如下:

db.collection.insert(
   <document or array of documents>,
   {
     writeConcern: <document>,
     ordered: <boolean>
   }
)

參數說明:

  • document:指定一個或多個文檔;
  • writeConcern:文檔寫入確認級別(可選),關於讀寫策略確認級別,以後再進行討論;
  • ordered:指定文檔是否按順序插入(可選),默認為true;
    • 當指定為true時,插入多個文檔時將文檔排序保存在一個數組中進行插入,如果其中有一個文檔插入失敗,則會導致數組中餘下的文檔不進行插入操作;
    • 當指定為false時,插入多個文檔時將文檔不進行排序保存在一個數組中進行插入,如果其中有一個文檔插入失敗,則不影響數組中餘下的文檔進行插入操作。

如果插入的文檔當中沒有指定_id字段,則MongoDB會自動為文檔生成具有唯一ObjectId值的字段_id

使用示例:

// 沒有指定_id字段的插入單個文檔
db.products.insert( { item: "card", qty: 15 } );

// 指定_id字段的插入單個文檔
db.products.insert( { _id: 10, item: "box", qty: 20 } );

// 插入多個文檔,不進行排序,多個文檔包含在數組[]中
db.products.insert(
   [
     { _id: 11, item: "pencil", qty: 50, type: "no.2" },
     { item: "pen", qty: 20 },
     { item: "eraser", qty: 25 }
   ]
);

// 插入多個文檔,並進行排序
db.products.insert(
   [
     { _id: 20, item: "lamp", qty: 50, type: "desk" },
     { _id: 21, item: "lamp", qty: 20, type: "floor" },
     { _id: 22, item: "bulk", qty: 100 }
   ],
   { ordered: false }
);

db.collection.insertOne()

語法格式如下:

db.collection.insertOne(
   <document>,
   {
      writeConcern: <document>
   }
)

參數說明:

參考db.collection.insert()的參數說明。

使用示例:

// 單行插入文檔,關於_id字段指定與否也與db.collection.insert()一致
db.products.insertOne( { item: "card", qty: 15 } );

db.collection.insertMany()

語法格式如下:

db.collection.insertMany(
   [ <document 1> , <document 2>, ... ],
   {
      writeConcern: <document>,
      ordered: <boolean>
   }
)

參數說明:

參考db.collection.insert()的參數說明。

使用示例:

參考db.collection.insert()的參數說明。

關於返回確認信息

db.collection.insert()在插入文檔成功之後返回的信息相對較為簡潔:

db.products.insert( { item: "card", qty: 15 } );
WriteResult({ "nInserted" : 1, "writeConcernError" : [ ] })

db.collection.insertOne()db.collection.insertMany()返回的信息較為詳細:

db.products.insertOne( { item: "card", qty: 15 } );
{
    "acknowledged": true,
    "insertedId": ObjectId("5eccbd214139000074003be8")
}

db.products.insertMany( [
      { _id: 10, item: "large box", qty: 20 },
      { _id: 11, item: "small box", qty: 55 },
      { _id: 12, item: "medium box", qty: 30 }
   ] );
{
    "acknowledged": true,
    "insertedIds": [
        10,
        11,
        12
    ]
}

查詢(Read Operations)

查詢(Read Operations)讀操作,是對集合中已存在的文檔進行查詢,即對應關係型數據庫當中的select操作,比如MySQL,MongoDB提供以下幾種主要查詢文檔方法:

  • db.collection.find():查詢指定集合中滿足條件的一個或多個文檔和視圖;
  • db.collection.findOne():查詢指定集合中滿足條件的第一個文檔,並以格式化方式展現,通過pretty()方法。

來自官方文檔的測試數據:

db.inventory.insertMany([
   { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
   { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },
   { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
   { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
   { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }
]);

db.collection.find()

db.collection.find()可以說是使用頻率最高的方法了,可以用來查詢數據庫集合當中的文檔。

語法格式如下:

db.collection.find(<query>, <projection>)
  • query:查詢表達式;
  • projection:指定查詢結果集中需要显示的字段。
    • Col_name:1|true 代表显示該字段;
    • Col_name:0 | false 代表不显示該字段。

_id字段是默認显示的,如果不想显示,則顯式指定{"_id" : 0}

查詢所有文檔:

db.inventory.find()

db.inventory.find({})

db.collection.findOne()

db.collection.findOne()方法显示符合條件查詢的第一條文檔,接受的參數與db.collection.find()方法一致。

條件查詢操作符

通常對文檔的查詢,是需要帶條件的,而很少使用到不帶條件的全文檔檢索,以下總結了幾種常使用的查詢操作符:

比較操作符

比較操作符涉及的操作如下錶所示:

名稱 說明
$eq 與指定值相等
$gt 大於指定的值
$gte 大於或等於指定的值
$in 指定的值在數組中
$lt 小於指定的值
$lte 小於或等於指定的值
$ne 所有不等於指定的值
$nin 指定的值不在數組中

使用示例:

// $eq:等值查詢 SQL: SELECT * FROM inventory WHERE status = "D";
db.inventory.find( { status: "D" } )

// $ne 同$eq

// $gt:範圍查詢(以大於為例) SQL: SELECT * FROM inventory WHERE qty > 30;
db.inventory.find( { qty: { $gt: 30 } } )

// $gte、$lt、$lte 同$gt

// $in:或查詢,可使用or代替 SQL: SELECT * FROM inventory WHERE status in ("A", "D")
db.inventory.find( { status: { $in: [ "A", "D" ] } } )

// $nin 同$in

邏輯操作符

邏輯操作符涉及的操作如下錶所示:

名稱 說明
$and 指定查詢同時滿足多個條件查詢子句
$not 指定查詢不滿足條件查詢子句
$nor 指定查詢無法滿足多個條件查詢子句
$or 指定查詢滿足其中某個條件查詢子句

使用示例:

// $and: 邏輯與查詢 SQL: SELECT * FROM inventory WHERE status = "A" AND qty < 30;
db.inventory.find( { $and: [ { status: { $eq: "A" },  qty: { $lt: 30 } } ] } )

// $not: 不符合查詢 SQL: SELECT * FROM inventory WHERE status <> "A";
db.inventory.find( { status: { $not: { $eq: "A" } } } )

/*
$nor: 無法同時滿足多個條件查詢,字段不存在時也符合 SQL: SELECT * FROM inventory WHERE status <> "A" AND qty > 30; 
符合以下條件之一都會出現在結果集中:
1.文檔包含status和qty字段並且符合條件;
2.文檔包含status字段並且符合條件,不包含qty字段;
3.文檔不包含status字段,包含qty字段並且符合條件;
4.文檔不包含status字段和qty字段。
*/
db.inventory.find( { $nor: [ { status: { $eq: "A" } },  { qty: { $lt: 30 } } ] } )

// $or: 邏輯或查詢 SQL: SELECT * FROM inventory WHERE status = "A" OR qty < 30;
db.inventory.find( { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } )

元素操作符

元素操作符主要涉及的操作如下錶所示:

名稱 說明
$exists 指定查詢文檔是否有對應的字段
$type 指定查詢文檔的某個字段是否是對應類型

使用示例:

// $exists: 是否存在指定字段查詢
db.inventory.find( { price: { $exists: true } } )

// $type: 字段是否是指定類型查詢
db.inventory.find( { "qty": { $type: "double" } } )

評估操作符

評估操作符主要涉及的操作如下錶所示,更多操作符可以參考官方文檔:https://docs.mongodb.com/manual/reference/operator/query-evaluation/

名稱 說明
$expr 為同一個文檔中的字段指定表達式並且符合條件的查詢,比如比較同一文檔當中兩個字段的值
$mod 為字段值取模並且符合條件的查詢

為了更好的使用這兩個主要的操作符,額外創建個文檔:

db.monthlyBudget.insertMany([
    { "_id" : 1, "category" : "food", "budget": 400, "spent": 450 },
    { "_id" : 2, "category" : "drinks", "budget": 100, "spent": 150 },
    { "_id" : 3, "category" : "clothes", "budget": 100, "spent": 50 },
    { "_id" : 4, "category" : "misc", "budget": 500, "spent": 300 },
    { "_id" : 5, "category" : "travel", "budget": 200, "spent": 650 }
]);

使用示例:

// $expr: 允許使用聚合表達式,這裏以$gt為例,更多表達式參考 https://docs.mongodb.com/manual/meta/aggregation-quick-reference/#aggregation-expressions
db.monthlyBudget.find( { $expr: { $gt: [ "$spent" , "$budget" ] } } )

// $mod: 對字段所在值進行取模運算,显示符合條件的查詢,如qty字段值對4取模,並且餘數為0
db.inventory.find( { qty: { $mod: [ 4, 0 ] } } )

更新(Update Operations)

更新(Update Operations)是對已存在的文檔進行修改操作,MongoDB提供以下幾種主要更新文檔方法:

  • db.collection.update():更新或替換集合中符合條件的一個或多個文檔;
  • db.collection.updateOne():只更新集合中符合條件的第一個文檔,即使有多個文檔(版本3.2新增);
  • db.collection.updateMany():更新集合中所有符合條件的文檔(版本3.2新增)。

db.collection.update()

根據update指定的表達式可以修改文檔中符合條件的字段或代替整個文檔。具體的語法格式如下:

db.collection.update(
   <query>,   //查詢表達式
   <update>,  //更新表達式
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ],
     hint:  <document|string>                   // 版本4.2新增
   }
)

參數說明:

  • query:更新文檔的查詢表達式;如果指定了參數upsert: true並且集合中沒有符合查詢條件的文檔,查詢條件中有關於字段_id指定了.分隔符的,並不會插入新的文檔;

  • update:主要包含三種格式

    • 1.更新文檔:只包含更新操作符表達式;
    • 2.替換文檔:只包含<field1>: <value1>對;
    • 3.聚合管道:版本4.2新增,詳細參考官方文檔。
  • upsert:當query查詢條件沒符合更新的文檔,就新創建文檔(可選),默認值為false

  • multi:是否更新多個符合條件的文檔(可選),默認值為false,只更新符合條件的第一個文檔;

  • writeConcern:參考db.collection.insert()相同參數說明;

  • collation:指定校對規則(可選,版本3.4新增);

  • arrayFilters:文檔數組更新過濾操作符(可選,版本3.6新增);

    詳細參考:https://docs.mongodb.com/manual/reference/method/db.collection.update/#specify-arrayfilters-for-array-update-operations

  • hint:採用文檔或字符串的形式指定適用於查詢表達式的索引,如果索引不存在則報錯(可選,版本4.2新增)。

使用示例:

使用示例將通過使用兩種場景進行,一是沒有使用參數選項upsert,二是使用參數選項upsert

  • 不使用選項upsert
// 測試數據
db.books.remove({});

db.books.insertMany([
  {
    "_id" : 1,
    "item" : "TBD",
    "stock" : 0,
    "info" : { "publisher" : "1111", "pages" : 430 },
    "tags" : [ "technology", "computer" ],
    "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ],
    "reorder" : false
   },
   {
    "_id" : 2,
    "item" : "XYZ123",
    "stock" : 15,
    "info" : { "publisher" : "5555", "pages" : 150 },
    "tags" : [ ],
    "ratings" : [ { "by" : "xyz", "rating" : 5 } ],
    "reorder" : false
   }
]);


/* 使用選項參數 upsert: true
1、如果查詢表達式找到匹配的文檔,則執行更新操作;
2、如果查詢表達式沒有找到匹配的文檔,則執行插入操作;
*/
db.books.update(
   { item: "ZZZ135" },   // 查詢表達式
   {                     // 更新或替換文檔
     item: "ZZZ135",
     stock: 5,
     tags: [ "database" ]
   },
   { upsert: true }
);

// 1.使用更新操作表達式
/* $set操作符
1、查詢表達式指定需要更新的文檔 _id;
2、$inc操作符: stock的字段值+5;
3、$set操作符: 替換item字段值,替換嵌入文檔info的publisher字段值,替換tags字段值,替換數組ratings的第二個元素值
*/
db.books.update(
   { _id: 1 },
   {
     $inc: { stock: 5 },
     $set: {
       item: "ABC123",
       "info.publisher": "2222",
       tags: [ "software" ],
       "ratings.1": { by: "xyz", rating: 3 }
     }
   }
);
更新之後的文檔:
{

  "_id" : 1,
  "item" : "ABC123",
  "stock" : 5,
  "info" : { "publisher" : "2222", "pages" : 430 },
  "tags" : [ "software" ],
  "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "xyz", "rating" : 3 } ],
  "reorder" : false
}

// 2.為已存在的數組添加元素
// $push操作符: 為指定文檔數組ratings添加一個元素
db.books.update(
   { _id: 2 },
   {
     $push: { ratings: { "by" : "jkl", "rating" : 2 } }
   }
);
更新之後的文檔:
{
  "_id" : 2,
  "item" : "XYZ123",
  "stock" : 15,
  "info" : {
   "publisher" : "5555",
   "pages" : 150
  },
  "tags" : [ ],
  "ratings" : [
   { "by" : "xyz", "rating" : 5 },

   { "by" : "jkl", "rating" : 2 }

  ],
  "reorder" : false
 }

// 3.文檔移除字段
// $unset操作符: 移除文檔的指定字段,為_id:1文檔移除tags字段
db.books.update( { _id: 1 }, { $unset: { tags: 1 } } );
更新后的文檔:
{
  "_id" : 1,
  "item" : "TBD",
  "stock" : 0,
  "info" : {
   "publisher" : "1111",
   "pages" : 430
  },
  "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ],
  "reorder" : false
 }

// 4.替換整個文檔
// 替換_id:2的文檔
db.books.update(
   { _id: 2 },
   {
     item: "XYZ123",
     stock: 10,
     info: { publisher: "2255", pages: 150 },
     tags: [ "baking", "cooking" ]
   }
);
更新后的文檔:
{
   "_id" : 2,
   "item" : "XYZ123",
   "stock" : 10,
   "info" : { "publisher" : "2255", "pages" : 150 },
   "tags" : [ "baking", "cooking" ]
}

// 5.更新多個文檔
db.books.update(
   { stock: { $lte: 10 } },
   { $set: { reorder: true } },
   { multi: true }
);
更新后的全部文檔:
[
  {
    "_id" : 1,
    "item" : "ABC123",
    "stock" : 5,
    "info" : {
     "publisher" : "2222",
     "pages" : 430
    },
    "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "xyz", "rating" : 3 } ],

    "reorder" : true

   }
   {
     "_id" : 2,
     "item" : "XYZ123",
     "stock" : 10,
     "info" : { "publisher" : "2255", "pages" : 150 },
     "tags" : [ "baking", "cooking" ],

     "reorder" : true

   }
]
  • 使用upserts選項
/* 使用選項參數 upsert: true
1、如果查詢表達式找到匹配的文檔,則執行更新操作;
2、如果查詢表達式沒有找到匹配的文檔,則執行插入操作;
*/

// 1.插入未符合更新條件的文檔
db.books.update(
   { item: "ZZZ135" },   
   {                     
     item: "ZZZ135",
     stock: 5,
     tags: [ "database" ]
   },

   { upsert: true }      

);
因為集合併未滿足條件的文檔,則插入的文檔為:
{
  "_id" : ObjectId("5da78973835b2f1c75347a83"),
  "item" : "ZZZ135",
  "stock" : 5,
  "tags" : [ "database" ]
}

// 2.插入未符合更新條件並且基於更新操作符的文檔
// 如果沒有符合更新查詢條件,並且使用的是更新操作符,則會基於當前的查詢條件和更新操作符字段插入新的文檔
db.books.update(
   { item: "BLP921" },   
   {                     
      $set: { reorder: false },
      $setOnInsert: { stock: 10 }
   },
   { upsert: true }      
);
新插入的文檔為:
{
  "_id" : ObjectId("5da79019835b2f1c75348a0a"),
  "item" : "BLP921",
  "reorder" : false,
  "stock" : 10
}

// 3.插入未符合更新條件並且基於聚合管道的文檔
// 關於聚合管道請參考官方文檔:https://docs.mongodb.com/manual/reference/method/db.collection.update/#update-with-aggregation-pipeline

// 4.插入未符合更新條件並且同時聯合多文檔操作符的文檔
如果不符合查詢條件,則只會插入單個文檔
db.books.update(
  { "info.publisher": "Self-Published" },   
  {                                         
    $set: { reorder: false, tags: [ "literature", "hardcover" ], stock: 25 }
  },
  { upsert: true, multi: true }             
);
新插入的文檔:
{
  "_id" : ObjectId("5db337934f670d584b6ca8e0"),
  "info" : { "publisher" : "Self-Published" },
  "reorder" : false,
  "stock" : 25,
  "tags" : [ "literature", "hardcover" ]
}

db.collection.updateOne()

根據update指定的參數可以修改文檔中符合條件的字段或代替整個文檔,與db.collection.update()不同的是每次只更新單個文檔。

語法格式如下:

db.collection.updateOne(
   <filter>,
   <update>,
   {
     upsert: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ],
     hint:  <document|string>        
   }
)

參數說明:

參考db.collection.update()的參數說明。

使用示例:

// 參考db.collection.update()

db.collection.updateMany()

根據update指定的參數可以修改文檔中符合條件的字段或代替整個文檔,與db.collection.updateOne()不同的是更新所有符合條件的文檔。

語法格式如下:

db.collection.updateMany(
   <filter>,
   <update>,
   {
     upsert: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ],
     hint:  <document|string>        
   }
)

參數說明:

參考db.collection.update()的參數說明。

使用示例:

// 參考db.collection.update()

刪除(Delete Operations)

刪除是指對集合當中已存在的文檔進行清除操作,MongoDB提供以下幾種主要刪除文檔方法:

  • db.collection.deleteOne():只刪除集合中符合條件的一個文檔;
  • db.collection.deleteMany():刪除集合中所有符合條件的文檔;
  • db.collection.remove():刪除集合中符合條件的一個或多個文檔。

db.collection.deleteOne()

根據filter選項條件刪除集合中的單個文檔,具體語法格式如下:

db.collection.deleteOne(
   <filter>,
   {
      writeConcern: <document>,
      collation: <document>
   }
)

參數說明:

  • filter:指定基於查詢表達式的過濾條件,關於查詢表達式可以查看db.collecion.find()中的<query>
  • writeConcern:參考db.collection.insert()相同參數說明;
  • collation:指定校對規則(可選,版本3.4新增);

使用示例:

// 刪除指定條件的單個文檔
db.orders.deleteOne( { "_id" : 1 } );
{ "acknowledged" : true, "deletedCount" : 1 }

db.collection.deleteMany()

根據filter選項條件刪除集合中的單個文檔,具體語法格式如下:

db.collection.deleteMany(
   <filter>,
   {
      writeConcern: <document>,
      collation: <document>
   }
)

參數說明:

參考db.collection.deleteOne()的參數說明。

使用示例:

// 刪除指定條件的多個文檔
db.orders.deleteMany( {"cust_id" : "Cam Elot"} );
{ "acknowledged" : true, "deletedCount" : 2 }

注意: 如果是對固定集合進行刪除文檔操作則會報錯,固定集合的清除操作使用方法db.collection.drop()

總結

  1. 本文簡單梳理了在Mongo Shell下基本的CRUD操作,主要適用於DBA的運維管理,如果是研發同學,根據不同的編程語言使用不同客戶端驅動進行操作,詳細同樣可以參考官方文檔;
  2. 針對CRUD各個方面還有其他一些額外的方法,比如查詢修改文檔方法db.collection.findAndModify(),這裏只是總結每個文檔操作中一些最基礎的方法,對於額外高級的方法這裏不再贅述;
  3. 掌握了這些基本的CRUD操作,就可以對MongoDB文檔進行操作了,但還是需要控制好權限,畢竟數據安全不是小事,做變更之前做好數據的備份,以防萬一。

參考

https://docs.mongodb.com/manual/crud/

https://docs.mongodb.com/manual/reference/operator/query-evaluation/

https://docs.mongodb.com/manual/reference/method/db.collection.update/#specify-arrayfilters-for-array-update-operations

https://docs.mongodb.com/manual/reference/method/db.collection.update/#update-with-aggregation-pipeline

〖本人水平有限,文中如有錯誤還請留言批評指正!〗

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※教你寫出一流的銷售文案?

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

Python面試常用的高級用法,怎麼動態創建類?

本文始發於個人公眾號:TechFlow,原創不易,求個關注

今天是Python專題的第16篇文章,今天我們來聊聊Python當中的元類。

元類是Python當中的高級用法,如果你之前從來沒見過這個術語或者是沒聽說過這個概念,這是非常正常的,因為一方面它的使用頻率不高,另外一方面就是它相對不太容易理解。以至於很多Python開發者都理解得不是很深入,導致了市面上相關的資料也並不太多。我也是讀了一些大牛的代碼才開啟了這扇新世界的大門。

一切都是對象

我們之前的時候曾經介紹過,在Python當中一切都是對象,注意,是一切都是對象。我們都知道對象是類實例化之後的結果,可以簡單地將類和對象類比成模具和成品的關係。模具是類,而根據模具做出來的產品是對象。

這個比喻思想比較接近,但是不完美。因為實際當中一個模具可以做出多個產品,一個產品只有一個模具。但編程語言當中不同,由於類之間可以繼承以及多繼承,也就是說一個對象可以對應多個類。所以這個比喻不是特別合適,但是類和對象的關係是沒錯的。

但是這就有了一個問題,既然Python當中一切都是對象,那麼是不是說類其實也是一個對象呢?也就是說一個模具其實也是另外一個模具的產品?同樣,這個模具的模具其實也是另外一個模具的產品,那麼我們一直追問下去會怎麼樣呢?

很簡單,我們做個實驗就知道了,我們可以用_class__關鍵字來查看一個變量的類型,那麼我們反覆調用就可以查看其中的關係了:

從上面的圖中我們可以發現,num是int類型的變量。我們繼續查看int這個類型的類型,得到了type類型。而當我們去查看type的類型的時候,會發現我們得到的還是一個type的類型。

所以我們可以明白了,type是Python中用來創建所有類的元類,是所有模具的模具。在Python當中,我們把一個類的類叫做元類(metaclass)。所以type就是Python當中內置的元類,我們也可以自己創建我們需要的元類。通過元類,我們創建的對象也是一個類,而不是一個實例。

動態創建類

理解了type是一切類基礎之後,再來看動態類就簡單了。動態類是動態語言最大的特性之一,作為典型的動態語言,Python自然也是支持類型的動態創建的。

在Python當中,創建動態類型的一種方式就是通過type關鍵字。說起來有些意想不到,type函數不是用來查詢對象所屬的類型的嗎,怎麼還可以創建類呢?

這其實是type的另外一種用法,作為元類來創建一個類。在這種用法,type函數接收3個參數,分別是類型的名稱,父類的元組,以及一個字典。除了第一個參數之外,後面兩個參數都可以為空。比如我們來看一個例子:

注意,type返回的結果是一個類,而不是一個實例。所以我們還可以通過它創建實例:

hello = Hello()

這樣創建出來的是最簡單的空類,它什麼也沒有,和下面的代碼等價。

class Hello:
    pass

我們也可以在type的參數當中為這個類填充屬性和方法:

def hello_world(self):
    print('hello')
    
Hello = type('Hello', (), {'hello':hello_world, 'num': 3})

這樣我們就為Hello這個類創建了一個方法叫做hello,一個屬性num等於3。我們可以來調用一下試試:

也就是說我們可以使用type來根據我們的需要自行定義類,只不過type既可以獲取對象的類型又可以創建新的類,看起來可能覺得有些不太直觀,但是其實這也是說得通的。我們在Python當中通過調用str創建一個string對象,通過int來創建一個integer對象,那麼通過type則是創建一個類的對象。

實現繼承

我們之前說了,當我們使用type來創建類的時候,還可以傳入父類的元組從而實現類的繼承。

比如我們再創建一個叫做World的類繼承剛才通過type創建出來的Hello類,然後在為它加上額外的函數:

def say_world(self):
    print('World')
    
World = type('World', (Hello, ), {'world': say_world})

注意這裏傳入第二個參數是父類的元組,既然是元組,那麼當元素只有一個的時候,需要加上逗號,表示這是一個元組。這樣創建出來的類和我們通過class定義的靜態類效果是一樣的:

也就是說,我們可以先把函數實現,然後再根據任務的需要把這些函數組裝成新的類。顯然,這和傳統的C++以及Java這些靜態類型的語言相比,要靈活得多。

總結

我們固然可以通過type來創建動態創建類,但是從上面的使用過程也應該看得出來,這樣使用起來並不太方便,並且很多進階的功能很難實現。舉個簡單的例子,比如我們想要動態地為一個已有的類添加一些動態的方法,生成新的類。我們使用type就很難實現。type也的確不是Python元類的主要運用,metaclass才是王道,但由於篇幅限制,這部分將放在下一篇文章當中。

當然,元類是一個非常高級的用法,以至於Python的創始人說99%的Python程序員並不需要用到它。所以如果你覺得理解起來非常費勁的話也沒有關係,知道這麼個概念就可以了。

今天的內容就是這些,如果喜歡本文,可以的話,請點個關注,給我一點鼓勵,也方便獲取更多文章。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

台中搬家公司費用怎麼算?

30萬以內教授看好的車型!但是它們都…

30萬以內更喜歡這些車型價格從低到高排列實際上,一輛車子賣不賣得好並不單單是車型本身的問題,4S店的門店數量、銷售的接待服務、售後管理都能直接影響到消費者的購車決定。作為一個“偽土豪”,周末的時間都會跑去4S店去看車。

平時看寫的導購文章已經夠多了,但是相信不少人還是選不到自己心儀的好車,這是正常的!市面上的車型選擇很多,一般面面俱到的車型價格都很貴,而我國汽車市場主要是集中在30萬這個區間內。有不少粉絲對的選車口味很感興趣,所以今天決定扒一扒30萬以內比較喜歡的車型,其實它們都是有一個共通點,那就是…

其實這是一個很普遍的現象,車評人眼中所看好的車型在市場上幾乎都是賣不好的貨色,而被我們黑就是垃圾的車型卻賣到瘋狂。原因很簡單,絕大部分消費者選車都偏向家用,選車需求:外觀要大氣、配置要高、空間要大、質量要穩定、操控是什麼?對於一個愛車之人,選車的要求則是:外觀帥、操控要好,動力要足、配置夠用就好、空間是什麼?兩種截然不同的選車理念已經決定車子賣得火不火的主要因素,畢竟“實用”才是眾多消費者的選擇,這才導致為什麼有這麼多“叫好不叫座”的車型出現。

30萬以內更喜歡這些車型

價格從低到高排列

實際上,一輛車子賣不賣得好並不單單是車型本身的問題,4S店的門店數量、銷售的接待服務、售後管理都能直接影響到消費者的購車決定。作為一個“偽土豪”,周末的時間都會跑去4S店去看車。跑得多你就能發現其實每一個品牌的4S店服務都有一定程度的差距,在必要的時候,還是會花錢買下來豐富一下自己家的車型庫(1:18模型)!

以所在的地區來說,在合資車型4S店中,個人感覺福特、別克的銷售一直都有着不錯的服務態度(基本的禮儀到位)、其次就是豐田、本田、大眾這一個檔次的,(看車的人比較多,銷售都沒空搭理你),最後就是馬自達這一類(看車的人沒幾個,但是銷售們也不會主動來搭理你)。

30萬以內,看上的車型其實不少!而今天說過的車型,除了宏光,其餘的都是賣不好的貨色,不過他們都有着各自的特點!高端品牌車型、改裝潛力極大的选手、駕控一流的选手,都是所喜愛的。不過為什麼不說SUV呢?因為中國SUV市場異常火爆,看上的SUV車型都賣得很好,就像昂科威、傳祺GS4、博越這一類的SUV都是很熱門的車型,是可以考慮的。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

※教你寫出一流的銷售文案?

※超省錢租車方案

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

本年度印象最深刻的四台轎車

作為一輛主打舒適的旅行車,2系旅行版已經做得足夠好了。從去年在海外上市,到今天由東本投產,十代思域可謂是颳起了一股屬於自己的旋風。1。5T發動機搭載6MT/CVT變速箱,能爆發出最大177馬力,不到8秒完成破百,加上不到13萬的起售價,這些標籤已經足以讓很多人瘋狂。

我們之前一共做了年度印象最深的性能車和SUV兩期大爆炸節目,今天,就該論到年度印象最深刻的轎車了。

奔馳S級在豪華級別車型中一直都是最強者般的存在,而之前新E級面世后,大家紛紛表示買這輛小S級就夠了。然而,試完S500L之後,我們認為還是太年輕了。

S500L的各方面的質感,完全是高E級一個檔次的,而它所搭載的4.0T V8發動機能提供相當有力道的動力輸出,這就已經和其他用着2.0T發動機的同級車型拉開差距了。

而無與倫比的後排乘坐體驗,真的讓人深深感嘆有錢真好。舒適度極高的座椅,坐到老闆位上之後,你就可以開始享受人生了。

雖然S級無論是自己開還是司機開,都會被人認為是司機,但是,S級的魅力真的很難讓人拒絕。

寶馬2系旅行版在換上了UKL前驅平台後,成為了首輛前驅寶馬。而大家一向對寶馬的認識就是直六發動機+后驅,而2系旅行版這樣一改,還得了?

但事實是,2系旅行版取消了后驅設定之後,整輛車的後排和後備廂空間得到了不少的提升。 畢竟是旅行版,所以兼顧家用才是它的屬性。作為一輛主打舒適的旅行車,2系旅行版已經做得足夠好了。

從去年在海外上市,到今天由東本投產,十代思域可謂是颳起了一股屬於自己的旋風。1.5T發動機搭載6MT/CVT變速箱,能爆發出最大177馬力,不到8秒完成破百,加上不到13萬的起售價,這些標籤已經足以讓很多人瘋狂。

雖然駕駛表現相當強勢,但十代思域犧牲了內飾造工來換取了更大的性能表現,就可能會讓一些想入手思域的朋友只能繼續觀望了。但是對於改裝愛好者來說,十代思域無疑是相當好的選擇之一。

不過,現在你想入手一輛思域,大部分地區還是要等待或是加價提車,這產能跟不上,想銷量瘋漲也很難。

CT6上市之初的定價使其擁有了相當強的價格優勢,加上驚艷的外觀設計,着實讓人覺得它能在風雲變幻的國內豪華車市場站穩腳跟。但可惜的是,由於種種原因,CT6並沒有取得理想的銷量。除去品牌知名度因素之後,實在想不到有更好的理由來解釋了。

但是,你只要試駕了這輛配有電磁懸挂和后轎轉向系統的CT6,你就會覺得它開起來根本不像一輛中大型轎車,甚至你要快開的時候,信心會更加充足。只可惜,如果你開的車型沒有配備這兩個神器的話,那麼你就會覺得它遠遠不如寶馬5系。

以上四輛車就是我們年度印象最深的轎車,各位敬請期待下一期印象最深的新能源車!本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

※產品缺大量曝光嗎?你需要的是一流包裝設計!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

拒絕PPT造車?蔚來汽車倫敦發布會的四大猜想

猜想三:神秘logo或為車標 暗含品牌名稱對於將要發布的品牌,目前找不到多少有價值的信息。兩周前蔚來汽車官方公眾號的一篇文章中,發布了一個圖形,外界猜測很可能就是未來量產車的車標,但這個品牌到底叫什麼至今不得而知。

距離11月21日蔚來汽車在倫敦發布品牌及電動超跑還有不到3天時間,官方卻依舊欲語還休,目前只公布了一個疑似的品牌logo和幾張超跑的局部照片,吊足胃口。

兩年前的這個時候,蔚來汽車成立,創始人李斌一再強調“我們不說沒有做到的事”,蔚來汽車也被業內視為“最靠譜”的新創車企。這場他們兩年以來正式舉辦的第一次發布會,想必是要兌現李斌許下的承諾了。

而一場發布會搞得如此神秘,不禁讓人聯想,到底又在憋什麼大招?

我們通過各種渠道搜集到一些信息,梳理出這場發布會的四大猜想。

猜想一:不走尋常路 藝術館里的發布會

不久前,蔚來官方宣布了即將在倫敦召開發布會,但是具體選址卻秘而不宣。直到我們近期拿到电子邀請函后,才知道此次發布會的舉辦地竟然是劍走偏鋒的倫敦薩奇藝術館(Saatchi Gallery)!

薩奇藝術館是一座專門收藏倫敦現代美術作品的藝術館,坐落於倫敦切爾西的帝王路,所有新生代藏品都是查爾斯·薩奇先生自身的收藏,這位讓英國當代藝術揚名世界的重要推手,在2010年將他的藏品和藝術館都捐贈給了政府。

作為倫敦文化地標,薩奇藝術館承辦過很多國際大型展覽,在2008年遷址開幕展中,張曉剛、方力鈞、岳敏君、王廣義、曾梵志、吳山專等24位中國當代藝術家的作品首次在此進行聯展。今年4月至9月,藝術館推出獻給滾石樂隊的第一個國際展覽,呈現樂隊50多年的歷史,展出超過500樣滾石樂隊物件。

蔚來汽車的發布會如何與薩奇藝術館相融合?炫酷的超跑如何跨界藝術空間?由於選址的特殊性,這次發布會的形式有可能打破大多科技品牌“一塊巨幕+一位主講人”的慣有思路!

猜想二:公布超跑性能數據 公開對抗邁凱倫

這款即將發布的跑車,是目前公開報道中第一台脫離了ppT、非概念、能在賽道上飛馳的實體電動跑車,蔚來汽車大約用了一年半時間造出了這款電動超跑,可以說是兌現了創始人李斌去年接受媒體採訪時許下的承諾。

此前多方都或隱晦或直接的說蔚來這款超跑能與邁凱倫p1和法拉利旗艦LaFerrari等頂級超跑抗衡。並且據稱這款超跑前不久在德國紐博格林北環進行了賽道速度測試,結果令人驚喜。但蔚來汽車官方對此沒有回應,這場發布會,官方是時候展現出蔚來在設計和技術方面的實力究竟幾何了。

猜想三:神秘logo或為車標 暗含品牌名稱

對於將要發布的品牌,目前找不到多少有價值的信息。兩周前蔚來汽車官方公眾號的一篇文章中,發布了一個圖形,外界猜測很可能就是未來量產車的車標,但這個品牌到底叫什麼至今不得而知。

我們從可靠渠道獨家獲悉,蔚來汽車對這個標誌的應用,或許有更多想法——很可能不僅僅只是一個車標。但這個車標究竟代表什麼意思?這個即將發布的品牌叫什麼名字?這些問題的答案也只能靜待發布會揭曉了。

猜想四:李斌李想“同框”直播發布會

2014年,汽車之家創始人李想在微博中寫了這麼一句話:爭取2015年結束之前,打造一款0-100公里/時實測加速在3秒之內的電動概念跑車出來。

2016年11月17日,他為這條微博畫上了句號:2014年吹的牛逼,在和李斌共同投資創辦蔚來汽車之後全部實現了,雖然晚了12個月,但是技術和產品更好。

他指的顯然就是蔚來汽車即將發布的這款超跑。

被業內親切稱作“李李”組合的李斌和李想,同為互聯網出身,他們創立的汽車之家和易車網是中國汽車垂直類網站的“百事和可口”。他們也曾各為其主,相爭七八年。

但蔚來汽車打破了外界對他倆關係的固有認知。李斌曾在採訪中透露,蔚來汽車是他和李想之間的個人合作,他們對汽車的未來,有着相似的洞察,即電動車對汽車行業的革命,不僅僅是環保節能,更多的是對汽車行業用戶體驗的重塑。

11月21日的這場發布會,可能成為他們聯手實現這個願景的第一步。李想在微博中透露,他會在國內與著名體育評論員段暄全程視頻直播蔚來倫敦發布會,並在直播中與李斌連線互動。屆時將出現極其罕見的“二李同框”場景,這究竟是什麼畫風,着實難以想象。

不過,儘管對蔚來汽車的諸多好奇得不到滿足讓人抓心撓肝,好在發布會馬上就要舉行。蔚來汽車將會帶領汽車行業打開一扇怎樣的大門,我們馬上就可以見到。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※推薦台中搬家公司優質服務,可到府估價

新形象新矩陣新高度 東風雪鐵龍全面刷新“收官”車展

基於信息化、数字化、雲計算未來使用的車輛間溝通、汽車周邊科技的研發。被動與主動安全融合建立汽車網絡安全體系, 2020年前實現所有新車聯網化。隨着神龍公司“E動戰略”的全面升級,東風雪鐵龍也將在旗下所有搭載渦輪增壓發動機的新車型上使用“pURETECH”的標識,以取代原有“發動機排量+T”的傳統動力標識。

作為本年度頂級汽車盛典,第十四屆中國(廣州)國際汽車展覽會今天拉開華麗大幕。東風雪鐵龍由全新越享高級轎車C6及新銳上市的2017款C3-XR領銜,率 T時代新C5、全新C4L、C4世嘉、全新愛麗舍、雪鐵龍全新C4 pICASSO等最新產品矩陣全力出擊萬眾矚目的“收官之戰”。

品牌新形象 更年輕,更具活力和創造力

伴隨着法系旗艦車型C6的榮耀上市,雪鐵龍全球品牌形象就此煥然一新。本屆車展儼然成為東風雪鐵龍“更年輕,更具活力和創造力”全新品牌形象的“T台秀”。

隨着80后、90後日漸成為新興購車主力,東風雪鐵龍也及時應對市場變化創新求變:品牌調性逐漸同年輕族群“接軌”、品牌特質逐步向年輕化滲透。 同時,品牌形象也開始大量融入時尚化元素,力求始終走在市場潮流的最前端。東風雪鐵龍甚至這樣表態:既可以讓消費者“任性”地在全系產品中挑選到他們自己認為時尚的車型,也可以為那些追崇個性、鄙夷“街車”的消費者量身定製。

無疑,給東風雪鐵龍超強信心的是一個歷經百年享譽世界的母品牌——雪鐵龍。因此,與生俱來就具備時尚、獨特和以人為本的優秀基因。這一品牌基因的完美傳承,正是東風雪鐵龍區隔其他品牌的獨特優勢,也自然而言與特立獨行的年輕消費族群產生強烈共鳴。

進入中國24年,東風雪鐵龍秉持“人性科技 創享生活”品牌理念,不斷通過旗下的產品和科技將“樂觀、人性、巧思”品牌價值帶給中國消費者。全新越享高級轎車C6的榮耀上市,不但彰顯了東風雪鐵龍“與眾不同 愉悅感受”獨特品牌優勢,更重要的是其代表着東風雪鐵龍最新的品牌形象和發展方向:更年輕、更有活力和創造力。

產品新矩陣 構築細分市場強大“火力網”

隨着社會經濟和居民可支配收入的持續增長,中國汽車消費者的購車觀念也隨之發生了巨大變化,逐漸從“實用”向“舒適”方向過渡。這是當前汽車消費趨勢中對法系車十分有利的“點”。這個趨勢不僅解決了法系車究竟在售賣什麼,也解決了法系車要往何處去的問題。

洞悉汽車舒適性與消費者對舒適性不斷提升的消費需求,雪鐵龍提出了“CITROËN ADVANCED COMFORT”(簡稱CAC)領先舒適設計理念,通過“過濾所有外部影響”、“讓車旅生活更加便捷”、“減少精神負荷”、“讓用車更加無縫相聯”四大方面來塑造消費者的舒適汽車生活,並將此指引未來雪鐵龍全球產品研發方向。

作為“CAC”理念下研發的的首款戰略車型,法系車旗艦C6完整詮釋了CAC全球產品設計理念,那就是愜意、便捷、凈謐、簡單這4大消費者核心利益點,為顧客帶來極致優越的全方位舒適享受。全新越享高級轎車C6自上市以來,憑藉比競品頂配車型低2萬元的售價讓消費者大呼“厚道”。除此之外,C6自身的產品力也不容小覷:豐富的標準配置、出色的底盤調校功力、以及細節方面體現出的卓越品質等都博得了消費者的嘖嘖稱道:這款車想不火都不成了!

在雪鐵龍新的設計理念下,東風雪鐵龍的產品定位將更加精準,也將更加符合年輕化的需求。同時,新產品新技術的市場投放速度越來越快。隨着全新越享高級轎車C6的上市,東風雪鐵龍全新產品矩陣已經形成。僅僅在今年,就陸續推出了全新愛麗舍2016款、全新C4L、全新越享高級轎車C6及C3-XR 2017款。“十三五”期間還將導入CMp及eCMp全新平台,加速進行不同市場覆蓋,新增覆蓋D級、C+SUV和MpV、LCV等市場;平均每年推出1~2款新車,共計15款新車,成為滿足客戶主流需求,覆蓋主要細分市場的主流品牌。

此外,將加速推進車載信息娛樂化、車聯網技術及智能化。基於信息化、数字化、雲計算未來使用的車輛間溝通、汽車周邊科技的研發;被動與主動安全融合建立汽車網絡安全體系, 2020年前實現所有新車聯網化。

隨着神龍公司“E動戰略”的全面升級,東風雪鐵龍也將在旗下所有搭載渦輪增壓發動機的新車型上使用“pURETECH”的標識,以取代原有“發動機排量+T”的傳統動力標識。目前,新的標識已率先安放在旗艦車型C6上。剛剛上市的C3-XR 2017款因為增加了230THp pureTech車型,所以“pureTech”的LOGO 也醒目“佩戴”在前格柵上。據悉,其他所有車型動力新標識的配置將於2017年年底前完成。通過全系T標識的升級,以及更加時尚、科技的產品魅力,東風雪鐵龍 “與眾不同 愉悅舒適”的獨特品牌魅力將更加凸顯。

服務新標高 勇奪2016CSI、SSI“雙冠王”

汽車市場增速放緩,隨之而來的就是競爭的加劇。東風雪鐵龍強烈意識到,謀取市場份額沒有捷徑可走,惟“給客戶提供最好的產品、最好的體驗和最好的服務”方能“精誠所至金石為開”最終贏得客戶的支持與信賴。

應對市場越來越嚴酷的競爭態勢,東風雪鐵龍將“服務創新+體系建設”作為全面提升客戶滿意度的兩大“推手”,並通過一系列行之有效的質量提升行動,讓自己的客戶滿意度連年保持增長。

此外,敢於創新的東風雪鐵龍相繼提出了“八大銷售流程、精益管理、領獎台計劃、30個動人時刻”,從戰略高度系統化地構建了品牌服務質量提升的基石。圍繞這4大方向,通過品牌長期堅持,實現了客戶售時滿意度和東風雪鐵龍品牌市場美譽度的雙提升。

根植中國24年,東風雪鐵龍始終秉承雪鐵龍創始人安德烈•雪鐵龍早在百年前就曾說過的一句經典名言:“汽車廠商賣的不僅僅是汽車,還有無微不至的服務”。延續百年傳承,東風雪鐵龍堅持在服務領域勇於創新永不止步,為此也收穫了累累碩果。

2016年7月28日, J.D. power2016年中國售後服務滿意度研究(CSI)報告正式發布。在主流車細分市場中,東風雪鐵龍以全行業最高分(814分)榮登榜首並成功衛冕。不僅如此,東風雪鐵龍還在J.D. power2016年中國汽車銷售滿意度研究(SSI)也名列主流汽車品牌第一位。藉此,東風雪鐵龍就成為唯一一個連續四年售時售後兩項滿意度排名均進入“前三甲”的主流汽車品牌。

2016年是東風雪鐵龍定義的“客戶體驗年”,在終端體驗方面,2017年開始將遵循雪鐵龍全球統一的全新形象標準,對自己的終端網絡進行升級,提升展廳的硬件設施和服務能力,以滿足未來全球化產品的投放需要和用戶體驗的需求。此外,按照全球統一標準,還將在一二線城市開展小型的體驗中心:雪鐵龍之家。

品牌新形象、產品新矩陣、服務新高度,帶着裡外“三新”參展的東風雪鐵龍想必是有備而來並且意欲大有斬獲。同樣可以預見,這“三新”也必將幻化為東風雪鐵龍早日躋身中國主流汽車品牌的“新引擎”。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

網頁設計最專業,超強功能平台可客製化

這有點猛!疑似 M1X 晶片的規格、效能跑分現身國外網站,12 核心 CPU + 16 核心 GPU

搭載 M1X 晶片 MacBook 可說是今年很多蘋果用戶最期待的產品之一,從 M1 來看,雖然已經知道這顆效能絕對不會差到哪去,但究竟有多強悍,相信不少人都想提前知道。而最近國外跑分網站就出現疑似 M1X 晶片的規格表,不僅非常猛,下方甚至還附上跑分比較表,如果是真的,那這顆實在有點誇張。

(圖片來源)

疑似 M1X 晶片的規格、效能跑分現身國外網站

近日國外 CPU Monkey 跑分網站上,出現一筆 Apple M1X 的跑分與規格資料,從下圖可以看到,這顆晶片採 5nm 製程技術,時脈雖然維持在 3.20GHz,但核心數提升到 12 顆,8 顆效能核心 + 4 顆節能核心。GPU 更誇張,核心數直接多一倍,變成 16 核心(M1 為 8 核心)。也有註明推出時間,預計在 2021 年的 Q2:

核心數跟去年底 LeasApplePro 爆料的 12 顆一樣,也增添這表格的可信度:

Next Mac March 12 cores

— LeaksApplePro (@LeaksApplePro) December 31, 2020

下方還有跑分數據圖,多核心相當猛,不過真實性還不知道,所以大家就參考即可,不用太認真看待。

首先是 Cinebench R23 單核心,時脈沒變,也因此分數當然跟 M1 差不多,獲得 1514 的同分表現:

Cinebench R23 多核心就超級猛,比 Ryzen 5700G 和 i9-10900X 還要高,獲得 14450 的分數:

Geekbench 5 64 位元單核心測試,也跟 M1 一樣,獲得 1744 的分數:

iGPU F32 效能測試,跟 M1 相比幾乎快提升一倍,拿下 5200 的超高分數:

如果到時 Apple 端出的 M1X 晶片真是這樣,那今年的新 Mac 看來也必入手不可阿,實在是讓人非常期待。

稍早也有消息指出,3/16 蘋果有可能舉辦春季新品發表會,不過預測新品表似乎沒有 Mac。

資料來源:CPU Monkey

針對 Apple M1 惡意軟體出現,安全自保守好三不

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

※別再煩惱如何寫文案,掌握八大原則!

確認以 GT 為名! realme GT 高通 S888 新旗艦將於 3/4 14:00 正式發表

昨(17)日我們才報導過 realme 副總裁徐起在微博暗示接下來 realme 的高通 Snapdragon 888 新旗艦將命名為 GT 系列的暗示,想不到在今(18)日稍早官方證實了此消息,同時預告 realme GT 的新機發表會時間就訂在 3 月 4 日。徐起也暗示 realme GT 不僅擁有 Snapdragon 888 的澎湃性能,還擁有持久續航和和高螢幕更新率。

▲圖片來源:徐起Chase(微博)

確認以 GT 為名! realme GT 高通 S888 新旗艦將於 3/4 14:00 正式發表

經過前幾天 realme 副總裁徐起在微博暗示 realme 這款內部代號「Race」的 Snapdragon 888 旗艦為 realme GT,稍早官方正式公開證實此消息,同時也預告 3 月 4 日下午 2 點舉行 realme GT 新機發表會。

▲圖片來源:徐起Chase(微博)

徐起在微博的貼文也提及 realme GT 將追求極致、挑戰「120% 的自己」,不過目前還無法肯定 120 的暗示是指 120Hz 螢幕更新率或 120W 快速充電。不過在 realme GT 首張官方宣傳海報左下角有三個圖示暗示 realme GT 的三大特色,從圖示推測由左至右依序為處理器、螢幕更新率和充電。根據過去的傳聞, realme GT 將搭載 Qualcomm Snapdragon 888 旗艦行動平台、 120Hz 螢幕更新率和 125W UltraDart 超級閃充。

▲圖片來源:徐起Chase(微博)

去年 7 月 16 亮相自家的 125W UltraDart 超級閃充技術 ,標榜只要充電 3 分鐘就能為 4000mAh 電池容量的手機充電達到 33% 電量。不過至今 125W UltraDart 超級閃充還未在 realme 旗下手機搭載,目前還是以 65W SuperDart 閃充為主流,不排除有機會在 realme GT 首次搭載。

▲圖片來源:realme真我手機(微博)

稍早數碼閒聊站在微博透露, realmeGT 將推出素皮和玻璃兩種版本,並提及在設計上有新東西:

▲圖片來源:數碼閒聊站(微博)

其實大約兩週前, realme GT 機身外觀就已經在中國工信部資料庫曝光,螢幕正面採用左上角採單挖孔的平面全螢幕設計,同時也採用光學螢幕下指紋辨識。在 realme GT 的機身背面下緣加入 GT 字樣。至於相機規格目前還無法得知,不過據過去傳聞將配備四鏡頭主相機設計。

▲圖片來源:TENAA

接下來在 3 月中旬前已經有多款新機即將陸續推出,目前可確認的依序為 2 月 22 日發表華為 Mate X2 、2 月 25 日發表紅米 Redmi K40 系列,以及 3 月 4 日將發表紅米 Redmi Note 10 系列和 realme GT 。另外,稍早 ROG 遊戲手機官方微博也確認新一代 ROG Phone 遊戲手機命名為 ROG Phone 5 ,在中國市場也是連續第三年和騰訊遊戲合作,預計也會在 3 月正式亮相。

消息來源:徐起Chase(微博)

延伸閱讀:
Redmi Note 10 系列確定將於 3/4 全球發表,相機與螢幕為此次升級重點

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!