Java Liskov替换和SRP原则违反-如何最好地构建此场景?

Java Liskov替换和SRP原则违反-如何最好地构建此场景?,java,c#,oop,design-patterns,object-oriented-analysis,Java,C#,Oop,Design Patterns,Object Oriented Analysis,在学习SRP和LSP的过程中,我试图改进代码的设计,以最好地符合这两个原则。我有一个employee类,上面有一个calculatePay方法。首先,我相信遵循OOP坚实的原则,calculatePay()方法不应该是员工的责任。员工的共同责任是执行任务()、午休时间()、打卡时间()和打卡时间()等。。我这样想对吗?这就是为什么我觉得calculatePay()应该属于其他类。好吧,这就是我的SRP不安全感 来到LSP: 我有子类,如会计师、推销员和董事。这些都是拿工资的员工。我将如何改变这种

在学习SRP和LSP的过程中,我试图改进代码的设计,以最好地符合这两个原则。我有一个employee类,上面有一个calculatePay方法。首先,我相信遵循OOP坚实的原则,calculatePay()方法不应该是员工的责任。员工的共同责任是执行任务()、午休时间()、打卡时间()和打卡时间()等。。我这样想对吗?这就是为什么我觉得calculatePay()应该属于其他类。好吧,这就是我的SRP不安全感

来到LSP:

我有子类,如会计师、推销员和董事。这些都是拿工资的员工。我将如何改变这种设计以更好地支持志愿者?志愿者没有报酬

public class Employee {

    private String name;
    private int salary;
    private boolean topPerformer;
    private int bonusAmount;


    public Employee(String name, int salary, boolean topPerformer, int bonusAmount) {
       // set fields etc..
    }

    // This method doesn't seem to belong here.
    public int calculatePay(){
        if(topPerformer)
            return salary+bonusAmount;
         else{
            return salary;
         }
    }
}

我同意你的看法,员工不能计算自己的工资。你永远不会要求员工这样做。在您的设计中,我将创建一个PayrollService类来计算员工的工资,并创建一个PaymentService来知道何时以及如何发送支票。遵循坚实的原则来精确定义有时是困难的


希望我正确理解了您的问题。

您实际上正在处理许多不同的实体

第一个实体是员工——你已经得到了

第二个实体是支付结构。正如您所看到的,最初的代码似乎很简单,直到您将志愿者添加到混合中

第三个是薪酬计算——领薪水的员工根据他们的表现获得不同的薪酬,而志愿者则得不到钱

当你认为不同的雇员与雇主有不同的契约关系时,生活变得更加有趣,这意味着他们拥有相同的“支付结构”,但他们的最终支付是不同的。第二,一名员工可以同时归入多个类别——一名受薪员工也可以从事志愿工作——这也是您需要将“薪酬结构”和“薪酬计算”划分为不同类别的另一个原因

为落实这些概念——

首先,通过添加“paymentstructure”类将payment结构移动到自己的类中,如下所示:

public PaymentStructure(salary, 
                        boolean topPerformer, 
                        int bonusAmount) {       
    // set properties for a salaried employee etc..
}

public PaymentStructure() {// default constructor = volunteer employee 
                           // set salary, bonusamount to 0, topPerformer to false, etc..
}
这样做还允许添加其他类型的付款计算输入,例如在完成工作时一次性付款等

接下来,如果只允许与员工建立单一付款关系,则需要更改员工构造函数以接受付款结构:

public Employee(String name, PaymentStructure PayStructureParm)
   // Save PayStructureParm to a class property 
}
然后编写一个类来实现支付计算逻辑:

public DeterminePayment(){
   public float calculatePayment(PaymentStructure PayStructureParm) { 
            // logic to turn the payment structure into a final payment 
     return finalPayment; }
}
这将员工、支付结构和支付计算拆分为各自的类,然后可以根据需要扩展所有这些类


为了获得更大的灵活性,这些类中的每一个都可以根据接口进行编码,而特定类型的支付结构和计算类则可以根据各自的接口进行编码

志愿者可以接受0美元的报酬吗?否则,子类型
PayedEmployee
(可能是一个接口)怎么样?不,零是个坏主意。我不想把一张支票寄回家给一个志愿者雇员,上面有0美元。那真是太遗憾了