1. 程式人生 > >開閉原則與里氏替換原則

開閉原則與里氏替換原則

1.開閉原則

是面向物件設計的基本原則之一,是“可複用設計”的基礎,它的主要原則是:對擴充套件開放,對修改關閉;意思就是我們改變一個軟體時。應該通過擴充套件方式來改變軟體,而不是修改原有的程式碼。

2.里氏替換原則

里氏替換原則是說,任何基類可以出現的地方,子類一定可以出現(只有當衍生類可以替換基類,軟體單位的功能不受到影響,基類才能真正被複用,衍生類也能夠在基類的基礎上增加新的行為)。

下面我們通過建一個專案,簡單實現一下,假如一個學生養了兩隻動物,一隻狗一隻貓,需要進行餵食(過程中匯入標頭檔案的操作省略,方法在.h中的宣告也省略,請自行新增)

1.需要建立的類有:

根檢視MainViewController,負責整體的呼叫與測試

繼承自NSobject的類Animal和繼承自Animal類的子類Cat和Dog

繼承自NSObject的類Student

2.在Animal類中實現一個方法:

-(void)eat
{
    NSLog(@"動物吃不同的東西");
}

然後在其子類Cat和Dog中重寫父類方法:
-(void)eat
{
    [super eat];
    NSLog(@"貓吃魚");
}

-(void)eat
{
    [super eat];
    NSLog(@"狗吃骨頭");
}

當然也要在Cat和Dog的標頭檔案中引入-(void)eat;不然Cat和Dog例項化的物件無法呼叫此方法

3.如果不使用開閉和里氏替換,則要在Student類中實現兩個餵養方法(匯入Cat和Dog的標頭檔案):

-(void)feedCat:(Cat*)cat
{
    NSLog(@"學生喂貓了");
    [cat eat];
}

-(void)feedDog:(Dog*)dog
{
    NSLog(@"學生喂狗了");
    [dog eat];
}

4.現在在MainViewController中的viewDidLoad中呼叫是這樣的:
Student *stu=[[Student alloc]init];
    Dog *dog=[[Dog alloc]init];
    Cat *cat=[[Cat alloc]init];
    [stu feedCat:cat];
    [stu feedDog:dog];

這種基本實現方式是可以的,也能實現,但是如果學生又餵了一隻烏龜,則又需要在Student中新增給烏龜餵食的方法,這種頻繁修改原始碼的方式不太可取,下面我們用上開閉原則和里氏替換原則,重複3和4的步驟;

3.只需要在Student類中實現一個餵養方法(匯入Animal的標頭檔案):

-(void)feed:(Animal*)animal
{
    NSLog(@"學生餵動物了");
    [animal eat];
}
4.在MainViewController中的viewDidLoad中需要這樣呼叫:
Student *stu=[[Student alloc]init];
    Animal *aCat=[[Cat alloc]init];
    Animal *aDog=[[Dog alloc]init];
    [stu feed:aCat];
    [stu feed:aDog];

這樣即使學生再餵養N只動物,Student裡面的程式碼也不需要再去修改(滿足了上面所說的開閉原則),大大減少了工作量,保持了程式碼的完整性;

這兩行

Animal *aCat=[[Cat alloc]init];
Animal *aDog=[[Dog alloc]init];
就是里氏替換,其本質就是用子類去例項化父類宣告的物件(即父類的指標指向子類開闢記憶體),然後呼叫子類內部的方法等。