面向对象设计中的方法

9

问题1:在我的大学面向对象建模和设计的学习中,他们推荐考虑对象的方法可以做什么以及它的属性对应的职责是什么。所有澄清的尝试都导致了进一步的困惑。

这往往会生成一个类图,其中演员具有所有动作,而内部类仅保存数据。

这似乎不正确。还有其他思考建模对象的方式吗?

问题2:此外,该课程似乎强调根据其真实世界的对应物对对象进行建模,但在域模型中并不一定合理。例如,在医疗实践中,他们有 Patient: CreateAppointment(),CancelAppointment() ,但实际上并不是这样实现的(您将修改约会集合)。是否有其他思考方式?

问题1示例

秘书:记录约会,记录约会取消

约会:时间、日期...(无方法)

问题2示例

医生:看病人

虽然“看病人”是用例,但在实际类上作为方法是没有意义的。你如何思考这个问题?


没有一种硬性和固定的方式。仅考虑 car.wheelCount 这一点过于简单化了所有不同有效方法。例如,在预约方面,似乎更“清晰”的做法是 doctorsOfficeSchedule.createAppointment(patient, ...)。也就是说,我倾向于以数据为导向而非“面向对象”。 - user166390
4个回答

11
很不幸,你遇到的障碍在学术界非常典型。学术项目往往以视频租赁店、图书馆或学生注册系统为起点(你的变体是医生办公室),然后通过动物来教授继承。你提供的指导方针也非常典型。
他们建议考虑对象在其方法中能够做什么,以及其属性对应的职责是什么。
事实上,当初学者询问时,我通常会解释一个对象的属性是它所知道的关于自己的事情,而它的方法是它知道如何执行的任务。这实际上只是另一种表述你所说的内容。正如你发现的那样,当你开始讨论更具体的系统而不仅仅是例子时,这种思考方式很快就会崩溃。
例如,该指南在以下对象中运作得非常好:
public class Tree
{
    public int Height { get; set; }
    public void Grow(int byHowMuch)
    {
        Height += byHowMuch;
    }
}

虽然这肯定符合要求,但你有权认为它感觉不对:

public class Secretary
{
    public void MakeAppoinment(Patient patient)
    {
        //make the appointment
    }
}

所以解决方案是什么?就是将所学应用起来。学习和理解设计模式将有助于开发比知道如何生长的树更加功能强大的系统。
推荐阅读: 为了解决你所面临的问题,我可能会使用继承个人类和接口的组合,它们将通过一系列服务类执行其操作。基本上,秘书、医生和患者都将从个人继承,并且每个这些类都可以传递到相应的服务类中。服务类可能会或可能不会执行像SeePatient()之类的操作。请不要认为这个例子意味着个人类不会有方法。
Stack Overflow有不少相关的问题,可能会有所帮助:

此外,建议查看以下内容:

最后,没有一个固定的定义来说明一个应用程序是面向对象的。如何应用模式、原则等将定义你的程序。你提出这些问题表明你正在走在正确的道路上。


0

我仍然感到困惑:“我是在告诉您做其他事情”还是“我正在做别人要求我的事情”?

也许你只需要玩芭比娃娃或G.I.乔来理解对象交互和责任的分配。G.I. Joe 受伤了(或者Barbie弄断了指甲),所以他打电话到医生办公室。“嘿,医生,我需要一个预约。” 因此,你作为孩子,告诉Barbie去看医生,谁需要知道该打给哪位医生以及如何拨打 - 一个引用和公共MakeAppointment()方法。 医生办公室需要把预约放在日程表上 - 这是自己的BookAppointment()方法,是医生办公室处理预约请求的流程。

public abstract GenderAppropriateDolly {
     protected DrOffice  Drkilldare;
     public override MakeAppointment() {throw new NotImplementedException();}
}


public class GIJoe : GenderAppropriateDolly {
    DrKilldare = new DrOffice();
    List<Appointment> myAppointments = new List<Appointment>;

    public void MakeAppointment () {
        myAppointments.Add(DrKilldare.BookAppointment(this));
    }
}

public class DrOffice {
    List<Appointment> officeAppointments = new List<Appointments>;

    public Appointment BookAppointment(GenderAppropriateDolly forWhom) {
       Appointment newappt = new Appointment(formWhom);
       this.Appointments.Add(newappt);

       return newappt;
    }    
}

public class Kid {
    GenderAppropriateDolly myRoleModel = new GIJoe();

    // Joe got wounded so ...
    myRoleModel.MakeAppointment();
}

0

你说得对,在许多情况下,更自然地包含行为的是高阶事物,比如系统或用户。

你可以将这种行为建模为类中的静态方法,这些方法操作数据模型。虽然它不是面向对象的,但没关系。你可以将相关方法分组到这样的类中,很快就会有“服务”的概念,就像面向服务的编程一样。

在Java中,有规范和标准来创建这样的类,即EJB中的无状态会话bean。Spring框架也有类似的概念,称为“Service”注解,可以应用于类以标记它们作为业务逻辑的外观。

因此,服务是封装系统中某种功能或行为的组件。它在给定的对象模型上运行(可以是其自己的内部模型,也可以是系统中更通用的业务对象模型)。如果你将你的用例与直接相关的服务联系起来,你可以编写非常易于维护的软件。

DCI Architecture是对此的正式化和尝试做同样的事情,但同时试图保持面向对象,通过根据需要向对象添加行为来实现。


0

问题1 您的对象的职责是否可以被解释为授权或合同要求,例如它们应该采取哪些操作?因此,以您在问题2中提到的医疗示例为例,具有调度程序角色(考虑C#/Java接口或Obj-C协议)的对象具有CanEditAppointments或EditsAppointments等属性。

问题2 从用例的角度来看,患者可能能够创建约会,因此您可能会在对象模型中实现一个Patient,并使用CreateAppointment()方法。但是,从封装的角度来看,您可能会在CreateAppointment()中实例化一个Appointment对象,然后调用Appointment对象上的方法或设置其时间、日期、患者、医生等属性。

由于约会集合很可能是像数据库这样的永久存储,因此将自己添加到集合的责任可能是约会对象的责任(Appointment.Schedule()通过数据访问层将自己保存到数据库中)。

这也与您在Q1中提到的有关,因为Appointment对象的职责是保存自身,所以它可能会实现一个ISaveAppointment接口,该接口需要字段和方法来执行它。同时,Appointment对象还需要在保存之前拥有日期、时间、患者等信息,因此ISaveAppointment接口应要求这些信息存在,并且Appointment.Schedule()应验证这些值是否正确或已经过先前验证。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接