再次编辑: 我想我现在明白了。我需要做的就是使用我希望能够访问的类的当前类冒号?人:学生或人:老师 这是对的吗?
我目前正在尝试学习面向对象编程的细节。目前我有一个新对象,如下所示:
class student
{
int grade; //0 - 100 as opposed to the characters A, B, C, etc.
string teacher; //For the teacher of the class the student is in.
}
class teacher
{
int courseAverage;
string name;
//teacher.name would correspond to the teacher in the student class.
}
class Program
{
student Jim;
Jim = new student();
teacher John;
John = new teacher();
}
static void grades()
{
Jim.grade = 100;
}
static void teacher()
{
Jim.teacher = "John Smith";
}
static void average()
{
int average; //For the sake of simplicity I'll leave the average at an int.
average = (Jim.grade + Sue.grade + Sally.grade + Robert.grade) / 4;
/*A loop would be set before the average variable to
ensure that only students of John would be counted in this.*/
}
static void teacheraverage()
{
John.courseAverage = average;//from the average method.
}
编辑:
我想做的是修改其他课程的信息。但是,我想从程序类中的方法中修改Jim学生的信息。一种计算具有给定教师的学生的平均成绩的方法。
另外,我在这些中使用静态的唯一原因是因为这是我设法跨方法访问变量的唯一方法。我尝试使用静态方法跨类使用这些方法但没有成功。还有另一种方法吗?
我想在多种方法中使用Jim学生。一个将设置Jim的成绩,另一个将设置老师。我想在这种情况下使用不同的方法,以便我可以了解它是如何完成的。
好吧,看起来我的理解不正确。我将尝试类方法中的方法。
答案 0 :(得分:5)
由于您使用的是C#,假设您使用的是.NET 3.5,您的类可能会看起来像这样:
public class Student
{
public int Grade { get; set; }
public string Teacher { get; set; }
}
Grade和Teacher是自动属性,大致相当于Java中的getter和setter,它们就是方法。 C#中的属性本质上是获取和设置类的本地成员的快捷方式。
您对上述课程的使用看起来像这样:
public class Program
{
// creates a new Student object with the properties Grade and Teacher set.
Student s = new Student() { Grade = 100, Teacher = "John Smith" }
Console.Write(s.Grade); // outputs 100
Console.Write(s.Teacher); // outputs John Smith
}
这是你要找的吗?
答案 1 :(得分:3)
嗯,至少有三种方式。
public class Student
{
int grade; //0 - 100 as opposed to the characters A, B, C, etc.
string teacher; //For the teacher of the class the student is in.
public void SetGrades()
{
grade = 100;
}
public void SetTeacher()
{
teacher = "John Smith";
}
}
class Program
{
public static void Main()
{
Student Jim;
Jim = new Student();
Jim.SetTeacher();
Jim.SetGrades();
}
}
或2.将学生传递给方法:
class Program
{
public static void Main()
{
Student Jim;
Jim = new Student();
grades(Jim);
teacher(Jim);
}
static void grades(Student student)
{
student.grade = 100;
}
static void teacher(Student student)
{
student.teacher = "John Smith";
}
}
或3.使用Jim作为Program类中的变量,所以你实际上不必将它传递给任何东西
class Program
{
static Student Jim;
public static void Main()
{
Jim = new Student();
grades();
teacher();
}
static void grades()
{
Jim.grade = 100;
}
static void teacher()
{
Jim.teacher = "John Smith";
}
}
请注意,在所有示例中,我使Student类的名称中包含一个大写的S,以区别于参数和您可能拥有的任何局部变量。
了解差异非常重要。
在第一个解决方案中,您要求对象本身设置成绩和教师。如果这些操作你做了很多,它们可能属于类本身,而不是在外面进行操作。
在第二个解决方案中,你绕过学生。这使您可以轻松地与多个学生一起工作,因为代码没有硬连线来处理单个对象。
在第三个解决方案中,您不必传递任何内容,但您的代码现在已锁定,只能在Jim字段中同时与一名学生一起工作。
就我个人而言,我会研究出第一种解决方案的变体,在设定的等级和教师方面只有一点灵活性。可能使用属性(你也应该考虑更多。)
答案 2 :(得分:1)
lassevk在回答你的问题方面做得很好 - 基本上,你如何通过多种方法访问名为Jim的Student实例。
但是,我想指出,你在这里做程序代码。并不是说这一定有什么问题 - 只是你没有真正“在这里”获得OO。
一个快速,2分钟的OO-ish方式的例子:
class Student {
public string Name { get; private set; }
public Student(string name) {
if (string.IsNullOrEmpty(name)) throw new ArgumentException();
this.Name = name;
}
}
class Teacher {
public string Name { get; private set; }
public List<Course> Courses { get; private set; }
public Grade GetAverageCourseGrade() {
int totalCourseGrade;
foreach (Course course in this.Courses) {
totalCourseGrade += course.GetAverageGrade().Value;
}
return new Grade(totalCourseGrade / this.Courses.Count);
}
public Teacher(string name) {
if (string.IsNullOrEmpty(name)) throw new ArgumentException();
this.Name = name;
this.Courses = new List<Course>();
}
}
class Course {
public string Name { get; private set; }
public IEnumerable<Student, Grade> StudentGrades { get; private set; }
public Grade GetAverageGrade() {
int totalGrade;
// could use LINQ, but I'll make it slightly more explicit
foreach (KeyValuePair<Student, Grade> studentGrade in this.StudentGrades) {
Grade grade = kvp.Value;
totalGrade += grade.Value;
}
return new Grade(totalGrade / this.StudentGrades.Count());
}
public Course(string name) {
if (string.IsNullOrEmpty(name)) throw new ArgumentException();
this.Name = name;
this.StudentGrades = new Dictionary<Student, Grade>();
}
}
class Grade {
public int Value { get; private set; }
public char Letter {
get {
switch (this.Value / 10) {
case 10: case 9:
return 'A';
case 8:
return 'B';
case 7:
return 'C';
case 6:
return 'D';
default:
return 'F';
}
}
}
public Grade(int value) {
if (value < 0 || value > 100) throw new ArgumentOutOfRangeException();
this.Value = value;
}
}
class Program {
static int Main(string[] args) {
Teacher john = new Teacher("John Smith");
Course cs101 = new Course("Computer Science 101");
john.Courses.Add(cs101);
Student mark = new Student("Mark Brackett");
Student xesaniel = new Student("Xesaniel");
cs101.Students.Add(mark, new Grade(90));
cs101.Students.Add(xesaniel, new Grade(95));
Console.WriteLine(john.GetAverageCourseGrade());
}
}
那里有很多仪式和噪音,但重要的是教师和课程知道如何计算他们自己的平均成绩并验证/执行他们自己的内部状态。 Main方法实际上只负责协调设置和类之间的任何交互。
从技术上讲,这里的很多关系是双向的 - 例如,教师有很多课程,而课程有一个老师。但是,双向关系可以是一个PITA来管理 - 而且这里没有令人信服的理由。
答案 3 :(得分:1)
你仍然缺少基本要点:类将数据与其方法相关联。因此设置Jim的老师的方法是Student类的一部分,如是设定吉姆成绩的方法。
首先用自然语言来思考。 “吉姆是一名学生;学生有姓名,擅长身份证号码和班级。班级有教师和教室。学生在学期末收到每个班级的成绩。”
所以我们有一个班级学生。学生,当你从中创建一个对象时,需要学生姓名和学生ID,所以“构造函数”需要是一个带有名字字符串和学生ID的东西 - 也称为字符串 - 来初始化它。我不知道C#,所以我会用括号制作一个伪咒......
class Student {
String name;
String studentID;
Course crsList = List<Course>; // "list of courses."
Student(String name, String studentID ){
// Make a new student, the "constructor"
this.name = name;
this.studentID = studentID;
}
addCourse(Course c){
// Add a course to the student's list
this.crsList.append(c); // Adds c to end of crsList
}
}
这表示“学生有姓名和身份证,我们可以在课程集合中添加课程。”
class Teacher {
String name;
Course crsList = List<Course>;
Teacher(String name){
this.name = name;
}
// ... more methods here.
}
但是我们观察到老师和学生都是两种人,所以我们“重构”这个以将共同的部分放在一起
class Person {
String name;
Person(String name){
this.name = name;
}
// ... more methods
}
现在我们改变老师和学生,所以我们说
class Student : Person {
String studentID;
Student(String name, String studentID){
// Now we need to initialize the Person part
super(name);
// and the special Student part
this.studentID = studentID;
}
}
现在说“学生是一种有额外学生证的人,我们可以添加课程。”
您将继续为Teach定义“addClass”,但作为Teacher类的一部分。为什么?因为为教师添加课程意味着不同于为学生添加课程。您将为学生添加一个课程和成绩的方法,找到课程并以某种方式分配他的成绩。 (流行测验:是课程或学生的一部分?)
答案 4 :(得分:0)
好的,这里有一个基本的误解。 你的方法与课程有关。你所拥有的基本结构与某些使用它们的功能有关;没错,但根本不是OO。
你真正想要的是这样的东西(希望是好的说明性伪代码):
class Person
name : String
Person(namearg: String) -- your constructor
name = namearg;
end
end
class Student :: Person -- read :: as "is a kind of"
Student(namearg : String)
super(namearg) -- calls the Person ctor
end
-- more stuff will go in here
end
-- Teacher looks much the same
class Course
courseName : String
teacher : Teacher
students : list of Student
Course(namearg : string)
courseName = namearg
end
addStudent(s : student)
students.append(s) -- add student to the end of the list
end
-- and so on.
end
关键是一个类知道它所描述的事物的所有内容:它使用的数据和可以执行的操作。
答案 5 :(得分:0)
您的模型过于简单且未明确。但是我们暂时忽略它; - )
在下面的示例中,我也忽略了属性的细节并对构造函数进行了存根,以免混淆主要的建模问题
学生和老师都是人(正如查理马丁和其他人指出的那样)
//people have names
public class Person
{
public Person(string _name)
{
Name = _name;
}
public string Name;
}
学生是一个人,有一个年级和一个老师
//students are people with a grade and a teacher
public class Student : Person
{
public Student(string _name, int _grade,
Teacher _teacher) : base(_name)
{
Grade = _grade;
Teacher = _teacher;
Teacher.Students.Add(this); //add to the teacher's collection
}
public int Grade;
public Teacher Teacher;
}
教师是人,具有课程平均成绩和一组学生。
public class Teacher : Person
{
public Teacher(string _name) : base(_name)
{
}
public int CourseAverage;
public IList<Student> Students = new List<Student>();
public void ComputeAverageGrade()
{
int sum = 0;
foreach(Student s in Students)
{
sum += s.Grade;
}
CourseAverage = sum / Students.Count;
}
}
在您的示例中,您有一些学生并计算平均成绩
public class Program
{
public static void Main(string [] args)
{
Teacher JohnSmith = new Teacher("John Smith");
Student Jim = new Student("Jim",100,JohnSmith);
Student Sue = new Student("Sue",90,JohnSmith);
Student Sally = new Student("Sally",70,JohnSmith);
Student Robert = new Student("Robert",100,JohnSmith);
//add our resident overachiever
Student JonSkeet = new Student("Jon Skeet",150,JohnSmith);
JohnSmith.ComputeAverageGrade();
Console.WriteLine("Course Average for " + JohnSmith.Name + " is " +
JohnSmith.CourseAverage.ToString());
}
}
在一个更现实的模型中,每个学生可能会参加一门以上的课程,每个教师可能会教授不止一门课程,因此您需要对课程进行建模。课程仅在学期或季度等期间存在。
答案 6 :(得分:0)
尝试将类视为制作机器的蓝图。对象是一台机器。当你使用它时,你不关心它是如何在里面工作的。您只需使用外部的各种控制杆和开关来控制它,并使用LED来告诉您答案,等等。这对你来说是一个“黑匣子”。
杠杆和开关是方法和属性。它们公开了一个“用户界面”,用于与对象进行交互。
方法内部的代码是内部的。它的工作原理是秘密。这使得对象更易于使用(如果它设计得很好)。最终存储信息的字段也是秘密。它们不能通过类方法之外的代码直接访问。
public class Student
{
// Notice how these details are private
private List<Subjects> _subjects = new List<Subjects>();
private DateTime _started;
// A property that only has a 'getter' because the value shouldn't be modified
public DateTime Started
{
get { return _started; }
}
// Methods carry out actions. This one calls on to a method in another object.
public void Enroll(Subject s)
{
if (_subjects.Contains(s))
throw new Exception("Already studying that course");
s.RegisterStudent(this);
_subjects.Add(s);
}
public void Flunk(Subject s)
{
if (!_subjects.Contains(s))
throw new Exception("Can't flunk that subject, not studying it");
s.RemoveStudent(this);
_subjects.Remove(s);
}
}
如果您采用这种方法,那么您就是在面向对象的过程中。你仍然需要学习很多有趣的东西 - 异常安全,遗传滥用,松散耦合......