几种类型的实例化
- 抽象类 - 不可以直接实例化
- 同样纯抽象类 - 接口,也不可以直接实例化
- 使用虚方法的类(有点半抽象的感觉),子类可以有选择的重写或者不重写
使用虚方法【virtual】的类:
子类可以有选择的重写或者不重写,直接继承后,不重写,直接调用基类代码,重写使用override关键字。
重写后调用基类代码:base.function();
++++++++++++++++++++++++++++++++++++++++++++++++++++++
虚方法必须有定义和实现,不然会触发 - CS0501的错误。
示例生成CS 0501:
“成员函数”必须声明一个主体,因为它没有标记为抽象、外部或部分。 非抽象方法必须有实现。
// CS0501.cs
// compile with: /target:library
public class clx
{
public void f(); // CS0501 declared but not defined
public void g() {} // OK
}
实例化场景
-
抽象类被作为基类使用后,派生类可以进行实例化,此时已经实现定义,可以实例化。
-
基类声明接口对象后,无法直接实例化,但是可以通过外部的类进行继承实现,在子类通过方法直接赋值给此对象 -【通过接口实现多态】-【面向接口编程】-【策略模式】
策略模式案例
增加了代码可重用性,易扩展性,可维护性。
设计原则:要针对接口编程,不要针对实现编程。
- 针对实现编程:
Dog dog = new Dog();
dog.Dark();
- 针对接口/父类编程:
Animal animal = new Dog();
animal.MakeSound()
只有在在运行是才指定具体实现的对象,我们一点不管他是什么类型,我们只关心他正确的实现MakeSound方法就好了。
下边是鸭子行为的接口和此行为的具体类。
- 定义接口-通用的模块
// 所有飞行行为的接口
public interface IFlyBehaviour
{
void Fly();
}
// 所有叫行为的接口
public interface IQuackBehaviour
{
void Quack();
}
- 实现接口-多态
// 使用翅膀飞
public class FlyWithWings : IFlyBehaviour
{
public void Fly()
{
//使用翅膀飞
Debug.Log("使用翅膀飞");
}
}
// 不会飞
public class FlyNoWay : IFlyBehaviour
{
public void Fly()
{
//什么都不做,不能飞
Debug.Log("什么都不做,不能飞");
}
}
// 呱呱叫
public class Quack : IQuackBehaviour
{
public void Quack()
{
//呱呱的叫
Debug.Log("呱呱的叫");
}
}
// 吱吱叫
public class Squeak : IQuackBehaviour
{
public void Quack()
{
//吱吱的叫
Debug.Log("吱吱的叫");
}
}
// 不会叫
public class MuteQuack : IQuackBehaviour
{
public void Quack()
{
//什么都不做,不会叫
Debug.Log("什么都不做,不会叫");
}
}
下面是鸭子的抽象类,关于抽象类需要注意以下几点:
① 抽象类只能用做其他类的基类。
② 抽象类可以包含抽象成员和普通的非抽象成员。
③ 抽象可以继承自另一个抽象类
④ 所有抽象类的成员必须使用override关键字实现。
⑤ 抽象类不能创建实例。
- 定义基类和接口对象
// 鸭子抽象类
public abstract class SuperNewDuck
{
public IFlyBehaviour flyBehaviour;
public IQuackBehaviour quackBehaviour;
//必须要实现的可以考虑抽象方法
public abstract void Swim();
public abstract void Display();
public void PerformFly()
{
//鸭子不会亲自处理飞的行为,而是委托给flyBehaviour引用的对象
flyBehaviour.Fly();
}
public void PerformQuack()
{
//鸭子不会亲自处理呱呱叫的行为,而是委托给quackBehaviour引用的对象
quackBehaviour.Quack();
}
public void SetFlyBehaviour(IFlyBehaviour flyType)
{
flyBehaviour = flyType;
}
public void SetQuackBehaviour(IQuackBehaviour quackType)
{
quackBehaviour = quackType;
}
}
- 下面是具体的鸭子派生类
// 野鸭
public class SuperMallardDuck : SuperNewDuck
{
public SuperMallardDuck()
{
flyBehaviour = new FlyWithWings();
quackBehaviour = new Quack();
}
public override void Display()
{
Debug.Log("外观是野鸭");
}
public override void Swim()
{
Debug.Log("在花式游泳");
}
}
// 木头鸭
public class SuperMecoyDuck : SuperNewDuck
{
public SuperMecoyDuck ()
{
flyBehaviour = new FlyNoWay();
quackBehaviour = new MuteQuack();
}
public override void Display()
{
Debug.Log("外观是木头鸭");
}
public override void Swim()
{
Debug.Log("在正常游泳");
}
}
//Unity测试代码...
public class DuckSimulator : MonoBehaviour
{
private void Start()
{
//实例一只野鸭
SuperNewDuck superMallardDuck = new SuperMallardDuck();
superMallardDuck.Display();
superMallardDuck.Swim();
superMallardDuck.PerformFly();
superMallardDuck.PerformQuack();
Debug.Log("--------动态改变鸭子飞行行为-----------");
//运行时改变飞行状态
superMallardDuck.SetFlyBehaviour(new FlyWithWings());
superMallardDuck.PerformFly();
}
}
这时新需求来了,要增加一只超级鸭子,他使用的是导弹飞行器,你怎么办?
① 添加FlyWithRocket类实现自IFlyBehaviour接口
② 给超级鸭子创建FlyWithRocket行为
设计原则:多用组合,少用继承。这里的少用并不是不用。
此设计模式名称:策略模式,他定义了算法族,分别封装起来。让他们之间可以互相替换,此算法独立于使用算法的客户。
设计谜题
设计谜题:
① 现在想象一下你要做一款动作冒险类(ACT)的游戏
② 有一个主角会使用武器
③ 但是同一时刻只能使用一种武器
④ 武器之间可以随意的切换
请你仔细想想你该怎么设计你的代码的架构并运用到游戏中去…

鬼泣5
好,现在来说说想法:
① 首先想到的应该是武器的抽象,将所有武器抽象成一个名为IWeaponBehaviour的接口,让其他的武器去实现这个接口,已达到动态改变行为的目的
② 然后就是角色的父类,具有配备武器的属性,战斗的属性,动态改变武器类型的属性
③ 你的代码结构可能如下
/// <summary>
/// 角色父类
/// </summary>
public class BaseCharacter
{
protected IWeaponBehaviour weaponBehaviour; //角色配备武器的属性
public virtual void fight() { } //战斗
public void SetWeapon(IWeaponBehaviour w) //切换武器
{
weaponBehaviour = w;
}
}
/// <summary>
/// 武器行为接口
/// </summary>
public interface IWeaponBehaviour
{
void useWeapon();
}
using UnityEngine;
/// <summary>
/// 武器巴雷特狙击枪
/// </summary>
public class Barrett : IWeaponBehaviour
{
public void useWeapon()
{
Debug.Log("使用巴雷特狙击枪");
}
}
using UnityEngine;
/// <summary>
/// 武器加特林
/// </summary>
public class Gatling : IWeaponBehaviour
{
public void useWeapon()
{
Debug.Log("使用武器加特灵机关枪");
}
}
using UnityEngine;
/// <summary>
/// 武器石头
/// </summary>
public class Stone : IWeaponBehaviour
{
public void useWeapon()
{
Debug.Log("使用石头攻击");
}
}
using UnityEngine;
/// <summary>
/// 武器剑
/// </summary>
public class Sword : IWeaponBehaviour
{
public void useWeapon()
{
Debug.Log("使用剑");
}
}
/// <summary>
/// 角色皇帝
/// </summary>
public class King : BaseCharacter
{
public King()
{
weaponBehaviour = new Barrett();
}
public override void fight()
{
weaponBehaviour.useWeapon();
}
}
/// <summary>
/// 角色皇后
/// </summary>
public class Queen : BaseCharacter
{
public Queen()
{
weaponBehaviour = new Gatling();
}
public override void fight()
{
weaponBehaviour.useWeapon();
}
}
/// <summary>
/// 角色骑士
/// </summary>
public class Knight : BaseCharacter
{
public Knight()
{
weaponBehaviour = new Sword();
}
public override void fight()
{
weaponBehaviour.useWeapon();
}
}
/// <summary>
/// 角色侏儒(或者叫哥布林哈哈)
/// </summary>
public class Troll : BaseCharacter
{
public Troll()
{
weaponBehaviour = new Stone();
}
public override void fight()
{
weaponBehaviour.useWeapon();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WarSimulator : MonoBehaviour
{
void Start()
{
BaseCharacter king = new King();
BaseCharacter queen = new Queen();
king.fight();
king.SetWeapon(new Sword());
king.fight();
Debug.Log("---------分割线----------");
queen.fight();
}
}
最后再来复习一下
① 此设计模式名为策略模式
② 其核心设计思想是封装可互相替换的算法和策略,每一个算法都独立于使用算法的客户