打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
数据结构与算法:04 C#面向对象设计 II

04 C#面向对象设计 II

知识结构:

图1 知识结构

5、属性

例1:属性概念的引入(问题)

图2 Class Diagram
public class Animal
{

public int Age;
public double Weight;
public bool Sex;
public Animal(int age, double weight, bool sex)
{
Age = age;
Weight = weight;
Sex = sex;
}
public void Eat()
{
Console.WriteLine("Animal Eat.");
}
public void Sleep()
{
Console.WriteLine("Animal Sleep.");
}
public override string ToString()
{
return string.Format("Animal Age:{0},Weight:{1},Sex:{2}",
Age, Weight, Sex);
}
}

class Program
{

static void Main(string[] args)
{
Animal al = new Animal(1, 1.2, false);
Console.WriteLine("Animal Age:{0},Weight:{1},Sex:{2}",
al.Age, al.Weight, al.Sex);
// Animal Age:1,Weight:1.2,Sex:False

al.Age = -1;
al.Weight = -0.5;
Console.WriteLine(al);
// Animal Age:-1,Weight:-0.5,Sex:False
}
}

例2:问题的解决(Java语言解决该问题的方案)

图3 Class Diagram
public class Animal
{

private int _age;
private double _weight;
private readonly bool _sex;
public int GetAge()
{
return _age;
}
public void SetAge(int value)
{
_age = (value > 0) ? value : 0;
}
public double GetWeight()
{
return _weight;
}
public void SetWeight(double value)
{
_weight = (value > 0) ? value : 0;
}
public bool GetSex()
{
return _sex;
}
public Animal(int age, double weight, bool sex)
{
_age = (age > 0) ? age : 0;
_weight = (weight > 0) ? weight : 0;
_sex = sex;
}
public void Eat()
{
Console.WriteLine("Animal Eat.");
}
public void Sleep()
{
Console.WriteLine("Animal Sleep.");
}
public override string ToString()
{
return string.Format("Animal Age:{0},Weight:{1},Sex:{2}",
_age, _weight, _sex);
}
}

class Program
{

static void Main(string[] args)
{
Animal al = new Animal(1, 1.2, false);
Console.WriteLine("Animal Age:{0},Weight:{1},Sex:{2}",
al.GetAge(), al.GetWeight(), al.GetSex());
// Animal Age:1,Weight:1.2,Sex:False

al.SetAge(-1);
al.SetWeight(-0.5);
Console.WriteLine(al);
// Animal Age:0,Weight:0,Sex:False
}
}

例3:属性的提出

图4 Class Diagram
public class Animal
{

private int _age;
private double _weight;
private readonly bool _sex;
public int Age
{
get { return _age; }
set { _age = (value > 0) ? value : 0; }
}
public double Weight
{
get { return _weight; }
set { _weight = (value > 0) ? value : 0; }
}
public bool Sex
{
get { return _sex; }
}
public Animal(int age, double weight, bool sex)
{
_age = (age > 0) ? age : 0;
_weight = (weight > 0) ? weight : 0;
_sex = sex;
}
public void Eat()
{
Console.WriteLine("Animal Eat.");
}
public void Sleep()
{
Console.WriteLine("Animal Sleep.");
}
public override string ToString()
{
return string.Format("Animal Age:{0},Weight:{1},Sex:{2}",
Age, Weight, Sex);
}
}

class Program
{

static void Main(string[] args)
{
Animal al = new Animal(1, 1.2, false);
Console.WriteLine("Animal Age:{0},Weight:{1},Sex:{2}",
al.Age, al.Weight, al.Sex);
// Animal Age:1,Weight:1.2,Sex:False

al.Age = -1;
al.Weight = -0.5;
Console.WriteLine(al);
// Animal Age:0,Weight:0,Sex:False
}
}

说明:C#在声明data时就可以定义setget方法。

  • get:定义读取操作。
  • set:定义赋值操作,value表示传入的参数值。

例4:属性的简化

图5 Class Diagram
public class Animal
{

private int _age;
private double _weight;
public int Age
{
get { return _age; }
set { _age = (value > 0) ? value : 0; }
}
public double Weight
{
get { return _weight; }
set { _weight = (value > 0) ? value : 0; }
}
public bool Sex { get; private set; }
public Animal(int age, double weight, bool sex)
{
_age = (age > 0) ? age : 0;
_weight = (weight > 0) ? weight : 0;
Sex = sex;
}
public void Eat()
{
Console.WriteLine("Animal Eat.");
}
public void Sleep()
{
Console.WriteLine("Animal Sleep.");
}
public override string ToString()
{
return string.Format("Animal Age:{0},Weight:{1},Sex:{2}",
Age, Weight, Sex);
}
}
class Program
{

static void Main(string[] args)
{
Animal al = new Animal(1, 1.2, false);
Console.WriteLine("Animal Age:{0},Weight:{1},Sex:{2}",
al.Age, al.Weight, al.Sex);
// Animal Age:1,Weight:1.2,Sex:False

al.Age = -1;
al.Weight = -0.5;
Console.WriteLine(al);
// Animal Age:0,Weight:0,Sex:False
}
}

6、索引器

6.1 定义

是集合类中的一种特殊属性,可使得集合类中的元素像数组元素一样访问。

6.2 语法结构

public 元素类型 this[int index]
{
get { ... }
set { ... }
}
public 元素类型 this[string name]
{
get { ... }
set { ... }
}

例5:利用索引器实现对集合类StudentSet中元素Student的访问。

图6 Class Diagram
public class Student
{

private string _name;
public string Name
{
get { return _name; }
set
{
_name = string.IsNullOrEmpty(value)
? "NULL"
: value;
}
}
public long ID { get; set; }
public Student(long id, string name)
{
ID = id;
_name = name;
}
public override string ToString()
{
return string.Format("ID:{0},Name:{1}", ID, Name);
}
}

public class StudentSet
{

private readonly int _maxCount = 500;
private readonly Student[] _stus;
public int Count
{
get; private set;
}
public StudentSet()
{
Count = 0;
_stus = new Student[_maxCount];
}
public void Add(Student stu)
{
if (stu == null)
throw new ArgumentNullException();
if (Count == _maxCount)
throw new IndexOutOfRangeException();

_stus[Count] = stu;
Count++;
}
public Student this[int index]
{
get
{
if (index < 0 || index > Count - 1)
throw new IndexOutOfRangeException();
return _stus[index];
}
set
{
if (index < 0 || index > Count - 1)
throw new IndexOutOfRangeException();

if (value == null)
throw new ArgumentNullException();
_stus[index] = value;
}
}
}

class Program
{

static void Main(string[] args)
{
StudentSet stuSet = new StudentSet();
stuSet.Add(new Student(10086, "张三"));
stuSet.Add(new Student(95988, "李四"));
stuSet[1].Name = string.Empty;
Console.WriteLine(stuSet.Count); // 2
Console.WriteLine(stuSet[0]); // ID:10086,Name:张三
Console.WriteLine(stuSet[1]); // ID:95988,Name:NULL
Console.WriteLine(stuSet[2]);
//未处理的异常: System.IndexOutOfRangeException: 索引超出了数组界限。
}
}

7、接口

7.1 概念

  • 接口是类设计的蓝图,即只提供声明而没有实现。
  • 接口不可以直接实例化对象(与抽象类相同)。
  • C#允许一个类实现多个接口(注意与继承的区别)。
  • 接口就是包含一系列不被实现的方法,而把这些方法的实现交给继承它的类。

7.2 表示

图7 Class Diagram

例6:根据类图利用Dog实现IAnimal接口

图8 Class Diagram
public interface IAnimal
{
int Age { get; set; }
double Weight { get; set; }
void Eat();
void Sleep();
}

public class Dog : IAnimal
{
private int _age;
private double _weight;
public int Age
{
get { return _age; }
set { _age = (value >= 0) ? value : 0; }
}
public double Weight
{
get { return _weight; }
set { _weight = (value >= 0) ? value : 0; }
}
public void Eat()
{
Console.WriteLine("Dog Eat");
}
public void Sleep()
{
Console.WriteLine("Dog Sleep");
}
}

class Program
{

static void Main(string[] args)
{
IAnimal al = new Dog();
al.Age = 1;
al.Weight = 2.5;
Console.WriteLine("Dog:Age={0},Weight={1}",
al.Age, al.Weight);
// Dog:Age=1,Weight=2.5
al.Eat();
// Dog Eat
al.Sleep();
// Dog Sleep
}
}

例7:利用接口实现“饲养系统”

某饲养员(Raiser)在目前状态下需要饲养三种动物:狗(Dog)、鸟(Bird)和鱼(Fish),该三种动物只需要让其睡觉(Sleep)和吃饭(Eat)即可。请设计该饲养系统,要求满足软件设计的“开闭原则”。

方案一:(在抽象类部分已经给出)

图9 利用抽象类实现饲养系统

方案二:

图10 利用接口实现饲养系统
public interface IAnimal
{
int Age { get; set; }
double Weight { get; set; }
void Eat();
void Sleep();
}

public class Bird : IAnimal
{
private int _age;
private double _weight;
public int Age
{
get { return _age; }
set { _age = (value >= 0) ? value : 0; }
}
public double Weight
{
get { return _weight; }
set { _weight = (value >= 0) ? value : 0; }
}
public void Eat()
{
Console.WriteLine("Bird Eat.");
}
public void Sleep()
{
Console.WriteLine("Bird Sleep.");
}
public void Fly()
{
Console.WriteLine("Bird Fly.");
}
}

public class Dog : IAnimal
{
private int _age;
private double _weight;
public int Age
{
get { return _age; }
set { _age = (value >= 0) ? value : 0; }
}
public double Weight
{
get { return _weight; }
set { _weight = (value >= 0) ? value : 0; }
}
public void Eat()
{
Console.WriteLine("Dog Eat.");
}
public void Sleep()
{
Console.WriteLine("Dog Sleep.");
}
public void Run()
{
Console.WriteLine("Dog Run.");
}
}

public class Fish : IAnimal
{
private int _age;
private double _weight;
public int Age
{
get { return _age; }
set { _age = (value >= 0) ? value : 0; }
}
public double Weight
{
get { return _weight; }
set { _weight = (value >= 0) ? value : 0; }
}
public void Eat()
{
Console.WriteLine("Fish Eat.");
}
public void Sleep()
{
Console.WriteLine("Fish Sleep.");
}
public void Swim()
{
Console.WriteLine("Fish Swim.");
}
}

public class Raiser
{

public void Raise(IAnimal al)
{
al.Eat();
al.Sleep();
}
}

class Program
{

static void Main(string[] args)
{
Raiser rsr = new Raiser();
rsr.Raise(new Dog());
// Dog Eat.
// Dog Sleep.

rsr.Raise(new Bird());
// Bird Eat.
// Bird Sleep.

rsr.Raise(new Fish());
//Fish Eat.
//Fish Sleep.
}
}

7.3 接口(interface)与抽象类(abstract class)

(1)相同点:

  • 接口与抽象类都不可以直接实例化对象。

(2)不同点:

  • 抽象类中的数据和操作必须有限制修饰符,而接口中的数据和操作不可以有限制修饰符。
  • 抽象类中可以有带实现体的方法(非abstract方法),而接口只能有方法的声明。
  • 抽象类在子类中通过override关键字覆写抽象方法,而接口被子类直接实现。

例8:一个类可以实现多个接口,但要注意多个接口中有重名方法的处理。

方式一:

图11 Class Diagram
public interface IHighWayWorker
{
void HighWayOperation();
void Build();
}

public interface IRailWayWorker
{
void RailWayOperation();
void Build();
}

public class Worker : IRailWayWorker, IHighWayWorker
{
public void HighWayOperation()
{
Console.WriteLine("HighWayOperation.");
}
public void RailWayOperation()
{
Console.WriteLine("RailWayOperation");
}
public void Build()
{
Console.WriteLine("HighWay,RailWay,Build.");
}
}

class Program
{

static void Main(string[] args)
{
Worker wr = new Worker();
wr.Build(); // HighWay,RailWay,Build.
IHighWayWorker hwr = new Worker();
hwr.Build(); // HighWay,RailWay,Build.
hwr.HighWayOperation(); // HighWayOperation.
IRailWayWorker rwr = new Worker();
rwr.Build(); // HighWay,RailWay,Build.
rwr.RailWayOperation();// RailWayOperation
}
}

方式二:

图12 Class Diagram
public interface IHighWayWorker
{
void HighWayOperation();
void Build();
}

public interface IRailWayWorker
{
void RailWayOperation();
void Build();
}

public class Worker : IHighWayWorker, IRailWayWorker
{
public void HighWayOperation()
{
Console.WriteLine("HighWayOperation.");
}
public void RailWayOperation()
{
Console.WriteLine("RailWayOperation");
}
void IHighWayWorker.Build()
{
Console.WriteLine("HighWay Build.");
}
void IRailWayWorker.Build()
{
Console.WriteLine("RailWay Build.");
}
// 注意:void IHighWayWorker.Build()和void IRailWayWorker.Build()
// 前面不能够加限制修饰符。
}

class Program
{

static void Main(string[] args)
{
Worker wr = new Worker();
//wr.Build(); 该语句错误
IHighWayWorker hwr = new Worker();
hwr.Build();//HighWay Build.
hwr.HighWayOperation();//HighWayOperation.
IRailWayWorker rwr = new Worker();
rwr.Build();//RailWay Build.
rwr.RailWayOperation();//RailWayOperation
}
}

8、泛型

例9:存储int数据类型的集合及操作。

public class IntSet
{

private readonly int _maxSize;
private readonly int[] _set;
public IntSet()
{
_maxSize = 100;
_set = new int[_maxSize];
//...
}
public void Insert(int k, int x)
{
//....
_set[k] = x;
}
public int Locate(int k)
{
//...
return _set[k];
}
}

class Program
{

static void Main(string[] args)
{
IntSet iSet = new IntSet();
iSet.Insert(0, 123);
int i = iSet.Locate(0);
Console.WriteLine(i); // 123
}
}

例10:存储string数据类型的集合及操作。

public class StringSet
{

private readonly int _maxSize;
private readonly string[] _set;
public StringSet()
{
_maxSize = 100;
_set = new string[_maxSize];
//...
}
public void Insert(int k, string x)
{
//....
_set[k] = x;
}
public string Locate(int k)
{
//...
return _set[k];
}
}

class Program
{

static void Main(string[] args)
{
StringSet strSet = new StringSet();
strSet.Insert(0, "abc");
string j = strSet.Locate(0);
Console.WriteLine(j); // abc
}
}

例11:利用object类存储通用数据类型的集合及操作。

public class GSet
{

private readonly int maxSize;
private readonly object[] _set;
public GSet()
{
maxSize = 100;
_set = new object[maxSize];
//...
}
public void Insert(int k, object x)
{
//....
_set[k] = x;
}
public object Locate(int k)
{
//...
return _set[k];
}
}

class Program
{

static void Main(string[] args)
{
GSet gSet1 = new GSet();
gSet1.Insert(0, 123);
int k1 = (int)gSet1.Locate(0);
Console.WriteLine(k1); // 123

GSet gSet2 = new GSet();
gSet2.Insert(0, "abc");
string k2 = (string)gSet2.Locate(0);
Console.WriteLine(k2); // abc

GSet gSet3 = new GSet();
gSet3.Insert(0, 123);
gSet3.Insert(1, "abc");//编译时可以通过,运行时出现异常。
int k3 = (int)gSet3.Locate(1); //这样使用存在类型安全问题。
Console.WriteLine(k3);
// 未处理的异常: System.InvalidCastException: 指定的转换无效。
}
}

泛型定义:即参数化类型。

在编译时用一个具体类型代替该参数类型,可定义类型安全的类而不影响工作效率。

例12:利用泛型T存储通用数据类型的集合及操作。

public class GSet<T>
{

private readonly int _maxSize;
private readonly T[] _set;
public GSet()
{
_maxSize = 100;
_set = new T[_maxSize];
//...
}
public void Insert(int k, T x)
{
//....
_set[k] = x;
}
public T Locate(int k)
{
//...
return _set[k];
}
}

class Program
{

static void Main(string[] args)
{
GSet<int> gSet1 = new GSet<int>();
gSet1.Insert(0, 123);
int k1 = gSet1.Locate(0);
Console.WriteLine(k1); // 123

GSet<string> gSet2 = new GSet<string>();
gSet2.Insert(0, "abc");
string k2 = gSet2.Locate(0);
Console.WriteLine(k2); // abc
}
}

我们把T称为类型参数,当然我们也可以对T进行约束。

例13:为类型参数T增加约束,比如T只能是值类型。

public class GSet<T> where T : struct
{

private readonly int _maxSize;
private readonly T[] _set;
public GSet()
{
_maxSize = 100;
_set = new T[_maxSize];
//...
}
public void Insert(int k, T x)
{
//....
_set[k] = x;
}
public T Locate(int k)
{
//...
return _set[k];
}
}

class Program
{

static void Main(string[] args)
{
GSet<int> gSet1 = new GSet<int>();
gSet1.Insert(0, 123);
int k1 = gSet1.Locate(0);
Console.WriteLine(k1); // 123

// GSet<string> gSet2 = new GSet<string>(); // 编译错误
// 错误 CS0453 类型“string”必须是不可以为 null 值的类型,
// 才能用作泛型类型或方法“GSet < T >”中的参数“T”
}
}

有关泛型约束可以查看以下图文:


9、类与类之间的关系

图13 依赖关系
public class Oxygen
{

//...
}

public class Water
{

//...
}

public abstract class Animal
{

public int Age;
public double Weight;
public abstract void Eat();
public abstract void Sleep();
public abstract void Breed();
public abstract void Metabolism(Oxygen o2, Water water);
}
图14 继承关系
public class Bird : Animal
{
public string Feather;
public void Fly()
{
//...
}
public void Egg()
{
//...
}
public override void Eat()
{
//...
}
public override void Sleep()
{
//...
}
public override void Breed()
{
//...
}
public override void Metabolism(Oxygen o2, Water water)
{
//...
}
}

public class Penguin : Bird
{
//...
}

public class Goose : Bird
{
//...
}

public class Duck : Bird
{
//...
}
图15 关联关系
public class Climate
{

//...
}

public class Penguin : Bird
{
private Climate _climate;
//...
}
图16 实现关系
public interface ILanguage
{
void Speak();
}
public class DonaldDuck : Duck, ILanguage
{
public void Speak()
{
//...
}
//...
}

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
unknown
[C#技术] .NET平台开源JSON库LitJSON的使用方法
C#基础方法和要点
解读C#中内部类的语法结构(1) - 51CTO.COM
C# 派生和继承(派生类与基类)
C# 字段和属性
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服