行為型SEQ9 - 策略模式 Strategy Pattern

【學(xué)習(xí)難度:★☆☆☆☆,使用頻率:★★★★☆】
直接出處:策略模式
梳理和學(xué)習(xí):https://github.com/BruceOuyang/boy-design-pattern
簡書日期: 2018/03/30
簡書首頁:http://www.lxweimin.com/p/0fb891a7c5ed

算法的封裝與切換——策略模式(一)

俗話說:條條大路通羅馬。在很多情況下,實(shí)現(xiàn)某個(gè)目標(biāo)的途徑不止一條,例如我們在外出旅游時(shí)可以選擇多種不同的出行方式,如騎自行車、坐汽車、坐火車或者坐飛機(jī),可根據(jù)實(shí)際情況(目的地、旅游預(yù)算、旅游時(shí)間等)來選擇一種最適合的出行方式。在制訂旅行計(jì)劃時(shí),如果目的地較遠(yuǎn)、時(shí)間不多,但不差錢,可以選擇坐飛機(jī)去旅游;如果目的地雖遠(yuǎn)、但假期長、且需控制旅游成本時(shí)可以選擇坐火車或汽車;如果從健康和環(huán)保的角度考慮,而且有足夠的毅力,自行車游或者徒步旅游也是個(gè)不錯(cuò)的選擇,大笑。

在軟件開發(fā)中,我們也常常會(huì)遇到類似的情況,實(shí)現(xiàn)某一個(gè)功能有多條途徑,每一條途徑對應(yīng)一種算法,此時(shí)我們可以使用一種設(shè)計(jì)模式來實(shí)現(xiàn)靈活地選擇解決途徑,也能夠方便地增加新的解決途徑。本章我們將介紹一種為了適應(yīng)算法靈活性而產(chǎn)生的設(shè)計(jì)模式——策略模式。

24.1 電影票打折方案

Sunny軟件公司為某電影院開發(fā)了一套影院售票系統(tǒng),在該系統(tǒng)中需要為不同類型的用戶提供不同的電影票打折方式,具體打折方案如下:

(1) 學(xué)生憑學(xué)生證可享受票價(jià)8折優(yōu)惠;

(2) 年齡在10周歲及以下的兒童可享受每張票減免10元的優(yōu)惠(原始票價(jià)需大于等于20元);

(3) 影院VIP用戶除享受票價(jià)半價(jià)優(yōu)惠外還可進(jìn)行積分,積分累計(jì)到一定額度可換取電影院贈(zèng)送的獎(jiǎng)品。

該系統(tǒng)在將來可能還要根據(jù)需要引入新的打折方式。

為了實(shí)現(xiàn)上述電影票打折功能,Sunny軟件公司開發(fā)人員設(shè)計(jì)了一個(gè)電影票類MovieTicket,其核心代碼片段如下所示:

//電影票類  
class MovieTicket {  
    private double price; //電影票價(jià)格  
    private String type; //電影票類型  

    public void setPrice(double price) {  
        this.price = price;  
    }  

    public void setType(String type) {  
        this.type = type;  
    }  

    public double getPrice() {  
        return this.calculate();  
    }  

         //計(jì)算打折之后的票價(jià)  
    public double calculate() {  
                  //學(xué)生票折后票價(jià)計(jì)算  
        if(this.type.equalsIgnoreCase("student")) {  
            System.out.println("學(xué)生票:");  
            return this.price * 0.8;  
        }  
                  //兒童票折后票價(jià)計(jì)算  
        else if(this.type.equalsIgnoreCase("children") && this.price >= 20 ) {  
            System.out.println("兒童票:");  
            return this.price - 10;  
        }  
                  //VIP票折后票價(jià)計(jì)算  
        else if(this.type.equalsIgnoreCase("vip")) {  
            System.out.println("VIP票:");  
            System.out.println("增加積分!");  
            return this.price * 0.5;  
        }  
        else {  
            return this.price; //如果不滿足任何打折要求,則返回原始票價(jià)  
        }  
    }  
}

編寫如下客戶端測試代碼:

class Client {  
    public static void main(String args[]) {  
        MovieTicket mt = new MovieTicket();  
        double originalPrice = 60.0; //原始票價(jià)  
        double currentPrice; //折后價(jià)  

        mt.setPrice(originalPrice);  
        System.out.println("原始價(jià)為:" + originalPrice);  
        System.out.println("---------------------------------");  

        mt.setType("student"); //學(xué)生票  
        currentPrice = mt.getPrice();  
        System.out.println("折后價(jià)為:" + currentPrice);  
        System.out.println("---------------------------------");  

        mt.setType("children"); //兒童票  
        currentPrice = mt.getPrice();  
        System.out.println("折后價(jià)為:" + currentPrice);  
    }  
}

編譯并運(yùn)行程序,輸出結(jié)果如下所示:

原始價(jià)為:60.0
---------------------------------
學(xué)生票:
折后價(jià)為:48.0
---------------------------------
兒童票:
折后價(jià)為:50.0

通過MovieTicket類實(shí)現(xiàn)了電影票的折后價(jià)計(jì)算,該方案解決了電影票打折問題,每一種打折方式都可以稱為一種打折算法,更換打折方式只需修改客戶端代碼中的參數(shù),無須修改已有源代碼,但該方案并不是一個(gè)完美的解決方案,它至少存在如下三個(gè)問題:

(1) MovieTicket類的calculate()方法非常龐大,它包含各種打折算法的實(shí)現(xiàn)代碼,在代碼中出現(xiàn)了較長的if…else…語句,不利于測試和維護(hù)。

(2) 增加新的打折算法或者對原有打折算法進(jìn)行修改時(shí)必須修改MovieTicket類的源代碼,違反了“開閉原則”,系統(tǒng)的靈活性和可擴(kuò)展性較差。

(3) 算法的復(fù)用性差,如果在另一個(gè)系統(tǒng)(如商場銷售管理系統(tǒng))中需要重用某些打折算法,只能通過對源代碼進(jìn)行復(fù)制粘貼來重用,無法單獨(dú)重用其中的某個(gè)或某些算法(重用較為麻煩)。

如何解決這三個(gè)問題?導(dǎo)致產(chǎn)生這些問題的主要原因在于MovieTicket類職責(zé)過重,它將各種打折算法都定義在一個(gè)類中,這既不便于算法的重用,也不便于算法的擴(kuò)展。因此我們需要對MovieTicket類進(jìn)行重構(gòu),將原本龐大的MovieTicket類的職責(zé)進(jìn)行分解,將算法的定義和使用分離,這就是策略模式所要解決的問題,下面將進(jìn)入策略模式的學(xué)習(xí)。

算法的封裝與切換——策略模式(二)

24.2 策略模式概述

在策略模式中,我們可以定義一些獨(dú)立的類來封裝不同的算法,每一個(gè)類封裝一種具體的算法,在這里,每一個(gè)封裝算法的類我們都可以稱之為一種策略(Strategy),為了保證這些策略在使用時(shí)具有一致性,一般會(huì)提供一個(gè)抽象的策略類來做規(guī)則的定義,而每種算法則對應(yīng)于一個(gè)具體策略類。

策略模式的主要目的是將算法的定義與使用分開,也就是將算法的行為和環(huán)境分開,將算法的定義放在專門的策略類中,每一個(gè)策略類封裝了一種實(shí)現(xiàn)算法,使用算法的環(huán)境類針對抽象策略類進(jìn)行編程,符合“依賴倒轉(zhuǎn)原則”。在出現(xiàn)新的算法時(shí),只需要增加一個(gè)新的實(shí)現(xiàn)了抽象策略類的具體策略類即可。策略模式定義如下: 策略模式(Strategy Pattern):定義一系列算法類,將每一個(gè)算法封裝起來,并讓它們可以相互替換,策略模式讓算法獨(dú)立于使用它的客戶而變化,也稱為政策模式(Policy)。策略模式是一種對象行為型模式。

策略模式結(jié)構(gòu)并不復(fù)雜,但我們需要理解其中環(huán)境類Context的作用,其結(jié)構(gòu)如圖24-1所示:

圖24-1 在策略模式結(jié)構(gòu)圖

在策略模式結(jié)構(gòu)圖中包含如下幾個(gè)角色:

  • Context(環(huán)境類):環(huán)境類是使用算法的角色,它在解決某個(gè)問題(即實(shí)現(xiàn)某個(gè)方法)時(shí)可以采用多種策略。在環(huán)境類中維持一個(gè)對抽象策略類的引用實(shí)例,用于定義所采用的策略。

  • Strategy(抽象策略類):它為所支持的算法聲明了抽象方法,是所有策略類的父類,它可以是抽象類或具體類,也可以是接口。環(huán)境類通過抽象策略類中聲明的方法在運(yùn)行時(shí)調(diào)用具體策略類中實(shí)現(xiàn)的算法。

  • ConcreteStrategy(具體策略類):它實(shí)現(xiàn)了在抽象策略類中聲明的算法,在運(yùn)行時(shí),具體策略類將覆蓋在環(huán)境類中定義的抽象策略類對象,使用一種具體的算法實(shí)現(xiàn)某個(gè)業(yè)務(wù)處理。

思考

一個(gè)環(huán)境類Context能否對應(yīng)多個(gè)不同的策略等級結(jié)構(gòu)?如何設(shè)計(jì)?

策略模式是一個(gè)比較容易理解和使用的設(shè)計(jì)模式,策略模式是對算法的封裝,它把算法的責(zé)任和算法本身分割開,委派給不同的對象管理。策略模式通常把一個(gè)系列的算法封裝到一系列具體策略類里面,作為抽象策略類的子類。在策略模式中,對環(huán)境類和抽象策略類的理解非常重要,環(huán)境類是需要使用算法的類。在一個(gè)系統(tǒng)中可以存在多個(gè)環(huán)境類,它們可能需要重用一些相同的算法。

在使用策略模式時(shí),我們需要將算法從Context類中提取出來,首先應(yīng)該創(chuàng)建一個(gè)抽象策略類,其典型代碼如下所示:

abstract class AbstractStrategy {  
    public abstract void algorithm(); //聲明抽象算法  
}

然后再將封裝每一種具體算法的類作為該抽象策略類的子類,如下代碼所示:

class ConcreteStrategyA extends AbstractStrategy {  
    //算法的具體實(shí)現(xiàn)  
    public void algorithm() {  
       //算法A  
    }  
}

其他具體策略類與之類似,對于Context類而言,在它與抽象策略類之間建立一個(gè)關(guān)聯(lián)關(guān)系,其典型代碼如下所示:

class Context {  
private AbstractStrategy strategy; //維持一個(gè)對抽象策略類的引用  

    public void setStrategy(AbstractStrategy strategy) {  
        this.strategy= strategy;  
    }  

    //調(diào)用策略類中的算法  
    public void algorithm() {  
        strategy.algorithm();  
    }  
}

在Context類中定義一個(gè)AbstractStrategy類型的對象strategy,通過注入的方式在客戶端傳入一個(gè)具體策略對象,客戶端代碼片段如下所示:

……  
Context context = new Context();  
AbstractStrategy strategy;  
strategy = new ConcreteStrategyA(); //可在運(yùn)行時(shí)指定類型  
context.setStrategy(strategy);  
context.algorithm();  
……

在客戶端代碼中只需注入一個(gè)具體策略對象,可以將具體策略類類名存儲(chǔ)在配置文件中,通過反射來動(dòng)態(tài)創(chuàng)建具體策略對象,從而使得用戶可以靈活地更換具體策略類,增加新的具體策略類也很方便。策略模式提供了一種可插入式(Pluggable)算法的實(shí)現(xiàn)方案。

算法的封裝與切換——策略模式(三)

24.3 完整解決方案

為了實(shí)現(xiàn)打折算法的復(fù)用,并能夠靈活地向系統(tǒng)中增加新的打折方式,Sunny軟件公司開發(fā)人員使用策略模式對電影院打折方案進(jìn)行重構(gòu),重構(gòu)后基本結(jié)構(gòu)如圖24-2所示:

圖24-2 電影票打折方案結(jié)構(gòu)圖

在圖24-2中,MovieTicket充當(dāng)環(huán)境類角色,Discount充當(dāng)抽象策略角色,StudentDiscount、 ChildrenDiscount 和VIPDiscount充當(dāng)具體策略角色。完整代碼如下所示:

//電影票類:環(huán)境類  
class MovieTicket {  
    private double price;  
    private Discount discount; //維持一個(gè)對抽象折扣類的引用  

    public void setPrice(double price) {  
        this.price = price;  
    }  

    //注入一個(gè)折扣類對象  
    public void setDiscount(Discount discount) {  
        this.discount = discount;  
    }  

    public double getPrice() {  
        //調(diào)用折扣類的折扣價(jià)計(jì)算方法  
        return discount.calculate(this.price);  
    }  
}  

//折扣類:抽象策略類  
interface Discount {  
    public double calculate(double price);  
}  

//學(xué)生票折扣類:具體策略類  
class StudentDiscount implements Discount {  
    public double calculate(double price) {  
        System.out.println("學(xué)生票:");  
        return price * 0.8;  
    }  
}   

//兒童票折扣類:具體策略類  
class ChildrenDiscount implements Discount {  
    public double calculate(double price) {  
        System.out.println("兒童票:");  
        return price - 10;  
    }  
}   

//VIP會(huì)員票折扣類:具體策略類  
class VIPDiscount implements Discount {  
    public double calculate(double price) {  
        System.out.println("VIP票:");  
        System.out.println("增加積分!");  
        return price * 0.5;  
    }  
}

為了提高系統(tǒng)的靈活性和可擴(kuò)展性,我們將具體策略類的類名存儲(chǔ)在配置文件中,并通過工具類XMLUtil來讀取配置文件并反射生成對象,XMLUtil類的代碼如下所示:

import javax.xml.parsers.*;  
import org.w3c.dom.*;  
import org.xml.sax.SAXException;  
import java.io.*;  
class XMLUtil {  
//該方法用于從XML配置文件中提取具體類類名,并返回一個(gè)實(shí)例對象  
    public static Object getBean() {  
        try {  
            //創(chuàng)建文檔對象  
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();  
            DocumentBuilder builder = dFactory.newDocumentBuilder();  
            Document doc;                             
            doc = builder.parse(new File("config.xml"));   

            //獲取包含類名的文本節(jié)點(diǎn)  
            NodeList nl = doc.getElementsByTagName("className");  
            Node classNode=nl.item(0).getFirstChild();  
            String cName=classNode.getNodeValue();  

            //通過類名生成實(shí)例對象并將其返回  
            Class c=Class.forName(cName);  
            Object obj=c.newInstance();  
            return obj;  
        }     
        catch(Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
    }  
}

在配置文件config.xml中存儲(chǔ)了具體策略類的類名,代碼如下所示:

<?xml version="1.0"?>  
<config>  
    <className>StudentDiscount</className>  
</config>

編寫如下客戶端測試代碼:

class Client {  
    public static void main(String args[]) {  
        MovieTicket mt = new MovieTicket();  
        double originalPrice = 60.0;  
        double currentPrice;  

        mt.setPrice(originalPrice);  
        System.out.println("原始價(jià)為:" + originalPrice);  
        System.out.println("---------------------------------");  

        Discount discount;  
        discount = (Discount)XMLUtil.getBean(); //讀取配置文件并反射生成具體折扣對象  
        mt.setDiscount(discount); //注入折扣對象  

        currentPrice = mt.getPrice();  
        System.out.println("折后價(jià)為:" + currentPrice);  
    }  
}

編譯并運(yùn)行程序,輸出結(jié)果如下:

原始價(jià)為:60.0
---------------------------------
學(xué)生票:
折后價(jià)為:48.0

如果需要更換具體策略類,無須修改源代碼,只需修改配置文件,例如將學(xué)生票改為兒童票,只需將存儲(chǔ)在配置文件中的具體策略類StudentDiscount改為ChildrenDiscount,如下代碼所示:

<?xml version="1.0"?>  
<config>  
    <className>ChildrenDiscount</className>  
</config>

重新運(yùn)行客戶端程序,輸出結(jié)果如下:

原始價(jià)為:60.0
---------------------------------
兒童票:
折后價(jià)為:50.0

如果需要增加新的打折方式,原有代碼均無須修改,只要增加一個(gè)新的折扣類作為抽象折扣類的子類,實(shí)現(xiàn)在抽象折扣類中聲明的打折方法,然后修改配置文件,將原有具體折扣類類名改為新增折扣類類名即可,完全符合“開閉原則”。

算法的封裝與切換——策略模式(四)

24.4 策略模式的兩個(gè)典型應(yīng)用

策略模式實(shí)用性強(qiáng)、擴(kuò)展性好,在軟件開發(fā)中得以廣泛使用,是使用頻率較高的設(shè)計(jì)模式之一。下面將介紹策略模式的兩個(gè)典型應(yīng)用實(shí)例,一個(gè)來源于Java SE,一個(gè)來源于微軟公司推出的演示項(xiàng)目PetShop。

(1) Java SE的容器布局管理就是策略模式的一個(gè)經(jīng)典應(yīng)用實(shí)例,其基本結(jié)構(gòu)示意圖如圖24-3所示:

圖24-3 PetShop訂單策略類結(jié)構(gòu)圖

【每次看到這個(gè)LayoutManager2接口,我都在想當(dāng)時(shí)Sun公司開發(fā)人員是怎么想的!微笑】

在Java SE開發(fā)中,用戶需要對容器對象Container中的成員對象如按鈕、文本框等GUI控件進(jìn)行布局(Layout),在程序運(yùn)行期間由客戶端動(dòng)態(tài)決定一個(gè)Container對象如何布局,Java語言在JDK中提供了幾種不同的布局方式,封裝在不同的類中,如BorderLayout、FlowLayout、GridLayout、GridBagLayout和CardLayout等。在圖24-3中,Container類充當(dāng)環(huán)境角色Context,而LayoutManager作為所有布局類的公共父類扮演了抽象策略角色,它給出所有具體布局類所需的接口,而具體策略類是LayoutManager的子類,也就是各種具體的布局類,它們封裝了不同的布局方式。

任何人都可以設(shè)計(jì)并實(shí)現(xiàn)自己的布局類,只需要將自己設(shè)計(jì)的布局類作為LayoutManager的子類就可以,比如傳奇的Borland公司(現(xiàn)在已是傳說)曾在JBuilder中提供了一種新的布局方式——XYLayout,作為對JDK提供的Layout類的補(bǔ)充。對于客戶端而言,只需要使用Container類提供的setLayout()方法就可設(shè)置任何具體布局方式,無須關(guān)心該布局的具體實(shí)現(xiàn)。在JDK中,Container類的代碼片段如下:

public class Container extends Component {  
    ……  
    LayoutManager layoutMgr;  
    ……  
    public void setLayout(LayoutManager mgr) {  
    layoutMgr = mgr;  
    ……  
    }  
    ……  
}

從上述代碼可以看出,Container作為環(huán)境類,針對抽象策略類LayoutManager進(jìn)行編程,用戶在使用時(shí),根據(jù)“里氏代換原則”,只需要在setLayout()方法中傳入一個(gè)具體布局對象即可,無須關(guān)心它的具體實(shí)現(xiàn)。

(2) 除了基于Java語言的應(yīng)用外,在使用其他面向?qū)ο蠹夹g(shù)開發(fā)的軟件中,策略模式也得到了廣泛的應(yīng)用。

在微軟公司提供的演示項(xiàng)目PetShop 4.0中就使用策略模式來處理同步訂單和異步訂單的問題。在PetShop 4.0的BLL(Business Logic Layer,業(yè)務(wù)邏輯層)子項(xiàng)目中有一個(gè)OrderAsynchronous類和一個(gè)OrderSynchronous類,它們都繼承自IOrderStrategy接口,如上圖,圖24-4所示。

在圖24-4中,OrderSynchronous以一種同步的方式處理訂單,而OrderAsynchronous先將訂單存放在一個(gè)隊(duì)列中,然后再對隊(duì)列里的訂單進(jìn)行處理,以一種異步方式對訂單進(jìn)行處理。BLL的Order類通過反射機(jī)制從配置文件中讀取策略配置的信息,以決定到底是使用哪種訂單處理方式。配置文件web.config中代碼片段如下所示:

……  
<add key="OrderStrategyClass" value="PetShop.BLL.OrderSynchronous"/>  
……

用戶只需要修改配置文件即可更改訂單處理方式,提高了系統(tǒng)的靈活性。

24.5 策略模式總結(jié)

策略模式用于算法的自由切換和擴(kuò)展,它是應(yīng)用較為廣泛的設(shè)計(jì)模式之一。策略模式對應(yīng)于解決某一問題的一個(gè)算法族,允許用戶從該算法族中任選一個(gè)算法來解決某一問題,同時(shí)可以方便地更換算法或者增加新的算法。只要涉及到算法的封裝、復(fù)用和切換都可以考慮使用策略模式。

1.主要優(yōu)點(diǎn)

策略模式的主要優(yōu)點(diǎn)如下:

(1) 策略模式提供了對“開閉原則”的完美支持,用戶可以在不修改原有系統(tǒng)的基礎(chǔ)上選擇算法或行為,也可以靈活地增加新的算法或行為。

(2) 策略模式提供了管理相關(guān)的算法族的辦法。策略類的等級結(jié)構(gòu)定義了一個(gè)算法或行為族,恰當(dāng)使用繼承可以把公共的代碼移到抽象策略類中,從而避免重復(fù)的代碼。

(3) 策略模式提供了一種可以替換繼承關(guān)系的辦法。如果不使用策略模式,那么使用算法的環(huán)境類就可能會(huì)有一些子類,每一個(gè)子類提供一種不同的算法。但是,這樣一來算法的使用就和算法本身混在一起,不符合“單一職責(zé)原則”,決定使用哪一種算法的邏輯和該算法本身混合在一起,從而不可能再獨(dú)立演化;而且使用繼承無法實(shí)現(xiàn)算法或行為在程序運(yùn)行時(shí)的動(dòng)態(tài)切換。

(4) 使用策略模式可以避免多重條件選擇語句。多重條件選擇語句不易維護(hù),它把采取哪一種算法或行為的邏輯與算法或行為本身的實(shí)現(xiàn)邏輯混合在一起,將它們?nèi)坑簿幋a(Hard Coding)在一個(gè)龐大的多重條件選擇語句中,比直接繼承環(huán)境類的辦法還要原始和落后。

(5) 策略模式提供了一種算法的復(fù)用機(jī)制,由于將算法單獨(dú)提取出來封裝在策略類中,因此不同的環(huán)境類可以方便地復(fù)用這些策略類。

2.主要缺點(diǎn)

策略模式的主要缺點(diǎn)如下:

(1) 客戶端必須知道所有的策略類,并自行決定使用哪一個(gè)策略類。這就意味著客戶端必須理解這些算法的區(qū)別,以便適時(shí)選擇恰當(dāng)?shù)乃惴āQ言之,策略模式只適用于客戶端知道所有的算法或行為的情況。

(2) 策略模式將造成系統(tǒng)產(chǎn)生很多具體策略類,任何細(xì)小的變化都將導(dǎo)致系統(tǒng)要增加一個(gè)新的具體策略類。

(3) 無法同時(shí)在客戶端使用多個(gè)策略類,也就是說,在使用策略模式時(shí),客戶端每次只能使用一個(gè)策略類,不支持使用一個(gè)策略類完成部分功能后再使用另一個(gè)策略類來完成剩余功能的情況。

3.適用場景

在以下情況下可以考慮使用策略模式:

(1) 一個(gè)系統(tǒng)需要?jiǎng)討B(tài)地在幾種算法中選擇一種,那么可以將這些算法封裝到一個(gè)個(gè)的具體算法類中,而這些具體算法類都是一個(gè)抽象算法類的子類。換言之,這些具體算法類均有統(tǒng)一的接口,根據(jù)“里氏代換原則”和面向?qū)ο蟮亩鄳B(tài)性,客戶端可以選擇使用任何一個(gè)具體算法類,并只需要維持一個(gè)數(shù)據(jù)類型是抽象算法類的對象。

(2) 一個(gè)對象有很多的行為,如果不用恰當(dāng)?shù)哪J剑@些行為就只好使用多重條件選擇語句來實(shí)現(xiàn)。此時(shí),使用策略模式,把這些行為轉(zhuǎn)移到相應(yīng)的具體策略類里面,就可以避免使用難以維護(hù)的多重條件選擇語句。

(3) 不希望客戶端知道復(fù)雜的、與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu),在具體策略類中封裝算法與相關(guān)的數(shù)據(jù)結(jié)構(gòu),可以提高算法的保密性與安全性。

練習(xí)

Sunny軟件公司欲開發(fā)一款飛機(jī)模擬系統(tǒng),該系統(tǒng)主要模擬不同種類飛機(jī)的飛行特征與起飛特征,需要模擬的飛機(jī)種類及其特征如表24-1所示:

表24-1 飛機(jī)種類及特征一覽表

為將來能夠模擬更多種類的飛機(jī),試采用策略模式設(shè)計(jì)該飛機(jī)模擬系統(tǒng)。

練習(xí)會(huì)在我的github上做掉

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,677評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,643評論 2 380

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

  • 1 場景問題# 1.1 報(bào)價(jià)管理## 向客戶報(bào)價(jià),對于銷售部門的人來講,這是一個(gè)非常重大、非常復(fù)雜的問題,對不同的...
    七寸知架構(gòu)閱讀 5,121評論 9 62
  • 設(shè)計(jì)模式匯總 一、基礎(chǔ)知識(shí) 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 3,961評論 1 15
  • 1 場景問題 1.1 報(bào)價(jià)管理 向客戶報(bào)價(jià),對于銷售部門的人來講,這是一個(gè)非常重大、非常復(fù)雜的問題,對不同的客戶要...
    4e70992f13e7閱讀 3,103評論 2 16
  • 設(shè)計(jì)模式基本原則 開放-封閉原則(OCP),是說軟件實(shí)體(類、模塊、函數(shù)等等)應(yīng)該可以拓展,但是不可修改。開-閉原...
    西山薄涼閱讀 3,848評論 3 14
  • 目標(biāo): 過級 實(shí)際情況:未通過 GOOD: 1.第二個(gè)片段的how有進(jìn)步 2.有回應(yīng)學(xué)習(xí)者提問 3.有主動(dòng)詢問學(xué)習(xí)...
    宗介山城分舵閱讀 195評論 0 0