有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何使实用程序类处理子类中的差异?

这可能是一个糟糕的例子,但请用它。我有一个超类Cake和两个子类:ExampleCakeSaleCake。我还有一个Baker可以对蛋糕进行反向工程,从而烘焙出一份蛋糕,并且知道之后该怎么处理它

(所有伪代码)

public class Cake{
   radius; 
   height;
   ingredients;
   color;
   name;
}

public class ExampleCake extends Cake{
   shelfLocation;
}

public class SaleCake extends Cake{
   owner;
}

public class Baker{
   Cake bakeCake(Cake);
   Cake bakeSaleCake(Cake, Owner);
   Cake bakeExampleCake(Cake, Location);

   void handleCake(Cake);
}

面包师需要知道如何处理普通蛋糕、示例蛋糕和销售蛋糕。所以他的BakeCae函数是这样的:

Cake bakeCake(cake){
   newCake = cake.copy();
   mixIngredients(newCake);
   putCakeInOven(newCake);
   putIcing(newCake);
   return cake;
}

Cake bakeSaleCake(cake, owner){
   newCake = bakeCake(cake);
   newCake.setOwner(owner);
   return newCake;
}

Cake bakeExampleCake(cake, location){
   newCake = bakeCake(cake);
   newCake.setLocation(location);
   return newCake;
}

void handleCake(cake){
   if(cake instanceof ExampleCake)
      putOnShelf((ExampleCake)cake);

   else if(cake instanceof SaleCake)
      giveToCustomer((SaleCake)cake);

   else
      putOnTable(cake);
}

我的问题是,面包师被硬编码为只处理特定类型的蛋糕。如果有新的蛋糕出现,他就吃不下了。有没有一种干净、通用的方法来处理这个问题,或者我上面的伪代码有点“足够好”(比如,它不会伤害你的眼睛或心脏)

谢谢


共 (2) 个答案

  1. # 1 楼答案

    要复制蛋糕,可以使用复制构造函数。这样就取决于具体的蛋糕如何复制自己。对于处理任意蛋糕,可以使用访客模式。通过访客,你可以“询问”蛋糕的类型,而不是用instanceof检查蛋糕的类型

    代码可能如下所示(除了复制构造函数之外,您还需要其他蛋糕构造函数):

    //蛋糕课

    public class Cake{
       int radius; 
       int height;
    
       public Cake(Cake cake){
           this.radius = cake.radius;
           this.height = cake.height;
       }
    
       <R> R accept(CakeVisitor<? extends R> visitor){
           return visitor.visit(this);
       }
    
    }
    

    //例如蛋糕类

    public class ExampleCake extends Cake{
       String shelfLocation;
    
       public ExampleCake(Cake cake, String shelfLocation){
           super(cake);
           this.shelfLocation = shelfLocation;
       }
    
       <R> R accept(CakeVisitor<? extends R> visitor){
           return visitor.visit(this);
       }
    
    }
    

    //蛋糕课

    public class SaleCake extends Cake{
       String owner;
    
       public SaleCake(Cake cake, String owner){
           super(cake);
           this.owner = owner;
       }
    
       <R> R accept(CakeVisitor<? extends R> visitor){
           return visitor.visit(this);
       }
    
    }
    

    //访客界面

    public interface CakeVisitor<R> {
    
        R visit(Cake cake); 
        R visit(SaleCake cake);
        R visit(ExampleCake cake);
    
    }
    

    //贝克班

    public class Baker {
        private final CakeVisitor<Void> cakeHandler = new CakeVisitor<Void>(){
    
            @Override
            public Void visit(Cake cake) {
                putOnTable(cake);
                return null;
            }
    
            @Override
            public Void visit(SaleCake cake) {
                giveToCustomer(cake);
                return null;
            }
    
            @Override
            public Void visit(ExampleCake cake) {
                putOnShelf(cake);
                return null;
            }
    
        };
    
        Cake bakeCake(Cake cake){
           return processedCake(new Cake(cake));
        }
    
        SaleCake bakeSaleCake(Cake cake, String owner){
           return processedCake(new SaleCake(cake, owner));
        }
    
        ExampleCake bakeExampleCake(Cake cake, String location){
           return processedCake(new ExampleCake(cake, location));
        }
    
        void handleCake(Cake cake){
            cake.accept(cakeHandler);
        }
    
        private <C extends Cake> C processedCake(C cake){
            mixIngredients(cake);
            putCakeInOven(cake);
            putIcing(cake);
            return cake;
        }
    }
    

    现在,如果你想和你的面包师一起处理一种新类型的蛋糕,它将被默认放在桌子上,除非你提供一个访问方法,该方法专门接受新蛋糕类型的对象。我认为你不能让它比这更通用,因为当你有一种新的蛋糕类型时,你想用不同于其他类型蛋糕的方式来处理它,而处理它的新代码必须在某个地方。像putOnTable()这样的代码不应该放在蛋糕类中,因为蛋糕不知道如何放在桌子上——面包师知道——>;因此,访客模式

  2. # 2 楼答案

    好的设计是识别哪些行为改变了,哪些保持不变,然后将这两个群体分开。这里发生的变化是面包师对每个蛋糕的行为。所以我们想创建一个新的类来封装他不断变化的行为。我们就是这样做的。使用一个名为doBehavior()的方法创建一个名为BakerBehavior的接口。然后,创建一个名为PutOnShelfBehavior的类和另一个名为GiveToCustomerBehavior的类,这两个类都实现了BakerBehavior行为。重写doBehavior()方法

    现在,在每个cake类中,都可以创建PutOnShelfBehavior对象或GiveToCustomerBehavior对象。您的cake超类将有一个act()方法,如下所示:

    //Constructor {
    myBehaviorObject=new PutOnShelfBehavior();
    }
    
    public void act() {
        myBehaviorObject.doBehavior();
    }
    

    现在,在你的面包师课上,这是你的手摇方法的样子:

    private void handleCake(Cake cake) {
        cake.act();
    }
    

    我看不出有其他方法可以做到这一点。这样做的好处是:A)不必在handleCake类中硬编码蛋糕类型,B)不必重复任何代码(例如,可能有两种不同的蛋糕类型放在货架上)。C) 每个蛋糕都不知道面包师的情况,只知道它会被放在架子上或其他什么东西上。我希望有人能告诉我是否有更好的方法,我对这个问题很感兴趣