Java 面向对象设计:可扩展和可维护的汽车商店系统
我昨天接受了一次采访,问了一个问题: 赛车存储系统: 该系统存储玩家可用的汽车信息Java 面向对象设计:可扩展和可维护的汽车商店系统,java,oop,design-patterns,Java,Oop,Design Patterns,我昨天接受了一次采访,问了一个问题: 赛车存储系统: 该系统存储玩家可用的汽车信息 两种换档策略:手动/自动 两种燃料:汽油/柴油 设计一个能够生产玩家要求的汽车的系统(如果 玩家想要一辆手动换档并燃用柴油的汽车,你的 系统应提供一个符合要求的汽车实例)。 系统应具有良好的可扩展性和可维护性 我的想法和解决方案: 我的想法是需求包含两个属性:装备和燃料。我计划制作一个包含属性和相应行为的抽象类。考虑到可伸缩性,将有一个界面可移动,其中包含汽车可以做的行为 如果将来添加了任何新属性,可以创建一
- 两种换档策略:手动/自动
- 两种燃料:汽油/柴油
可移动
,其中包含汽车可以做的行为
如果将来添加了任何新属性,可以创建一个包含新属性的新抽象类,也可以将该属性添加到现有的抽象类中。如果需要新的行为,我将创建新接口或将该行为添加到现有接口中
以下是我所做的:
接口包含常规行为,当前仅具有showSpecs()
public interface Movable {
public String showSpecs();
}
抽象类包含属性fuel
和gear
public abstract class Car implements Movable {
String gear;
String fuel;
abstract void setFuel(String fuel);
abstract String getFuel();
abstract void setGear(String gear);
abstract String getGear();
}
现在,赛车等级实施:
public class RaceCar extends Car {
public RaceCar(String fuel, String gear) {
this.fuel = fuel;
this.gear = gear;
}
public void setFuel(String fuel) {
this.fuel = fuel;
}
public String getFuel() {
return this.fuel;
}
public void setGear(String gear) {
this.gear = gear;
}
public String getGear() {
return this.gear;
}
public String showSpecs() {
StringBuilder sb = new StringBuilder();
sb.append("Gear:").append(this.gear);
sb.append("Fuel:").append(this.fuel);
return sb.toString();
}
}
以下是我的主要课程:
public class Main {
public static void main(String[] args) {
System.out.println("get started...");
Car car = new RaceCar("diseal", "automatic");
System.out.println(car.showSpecs());
}
}
面试官回答说,我提供的解决方案不可扩展,很难维护,但没有提供细节,所以我仍然对自己犯了哪些错误以及如何改进感到困惑
谁能帮我分享一下你的想法,并指出我应该改进什么
谢谢 我会用两个类回答这个问题,
Car
和CarBuilder
:
public final class Car {
private final Fuel fuel;
private final Gears gears;
public Car(Fuel fuel, Gears gears) {
this.fuel = fuel;
this.gears = gears;
}
public Fuel getFuel() {
return fuel;
}
public Gears getGears() {
return gears;
}
enum Fuel {
GASOLINE,
DEISEL
}
enum Gears {
AUTOMATIC,
MANUAL
}
}
public class CarBuilder {
//sensible defaults:
private Car.Fuel fuel = Car.Fuel.GASOLINE;
private Car.Gears gears = Car.Gears.MANUAL;
public CarBuilder() {
}
public CarBuilder withFuelType(Car.Fuel fuel) {
this.fuel = fuel;
return this;
}
public CarBuilder withGearBox(Car.Gears gears) {
this.gears = gears;
return this;
}
public Car build() {
return new Car(this.fuel, this.gears);
}
}
可伸缩性和可维护性是通过以下事实实现的:如果需求发生变化,这两个类是未来需要更改的唯一两个类Car
是不可变的,并且还包含表示其内部状态所需的枚举,因此这些属性不能泄漏到上下文/对象之外,因为它们在上下文/对象中是有意义的,所以以后更容易维护
builder类虽然是当前形式的基本类,但可以扩展以适应更复杂的构造需求,而不会将实现细节泄漏到Car
类中
默认值是可选的,但可能有意义
汽车可以这样构造:
//Default car:
Car car = new CarBuilder().build();
//Customised car:
Car car = new CarBuilder().withFuelType(Car.Fuel.DEISEL).withGearBox(Car.Gears.AUTOMATIC).build();
当他提到可伸缩性和可维护性时,我想他可能期待类似可插拔类的东西。所以我认为这种战略模式可能是意料之中的。如果传输或注入需要执行一些真正的逻辑,我可以假设它们是行为,而不仅仅是状态。因此,这一实现会产生结果
公共接口传输策略{
公共无效传输();
}
公共类AutomaticTransmission实现传输策略{
公共无效传输(){
//在这里做一些真正的逻辑
打印(“自动…”);
}
}
公共类手册变速箱执行变速箱策略{
公共无效传输(){
print(“我们喜欢它…”);//这只是一个非常简单的逻辑示例
}
}
公共接口注入策略{
公开无效注入();
}
公共类柴油喷射实施喷射策略{
公共图书馆{
印刷品(“柴油机”);
}
}
公共级汽油注入实施注入策略{
公共图书馆{
打印(“汽油…”);
}
}
公车{
公共无效生成(传输策略传输,注入策略注入){
//设置其他部分
传输。传输();
//设置其他部分
injection.injection();
//其他部分
}
}
//--------------在某些客户的某个地方--------------------
汽车=新车();
//实际上,要真正实现可配置,请在此处使用工厂方法。
汽车制造(新手动变速器(),新汽油喷射器());
如果这是意料之中的,那么只要使用lambdas或命令模式,它也会被创建。我可能会向他施压,要求他定义一个比“好”稍微好一点的需求。你在需求方面过于复杂了,因为似乎不需要
可移动
或汽车
:只需定义赛车
类;给它两个字段;给它一个构造函数。定义燃油和汽车字段值的枚举。但是可伸缩性——我很难理解实际需要什么:每次需要实例时都调用构造函数;仅仅调用构造函数似乎是必要和足够的。我不喜欢使用普通的String
s作为属性。更好地使用枚举(或者其他一些,这取决于这些实例的实际使用方式)。我不太喜欢这些需求,因为它们没有告诉我们如何使用这些实例。这使得设计不仅仅是通用的东西变得困难。也许他们期待工厂模式或战略模式。谁知道…@AndyTurner谢谢Andy的回复。我曾经问过人们期望什么样的可伸缩性,得到的答案是“添加坦克”。我没有提到细节,因为一位面试官看到了源代码,他说这不是他期望的答案。这个问题对我来说很模糊,我问了几个问题,但没有得到明确的回答。我认为它可能是开放的,因为“可伸缩性”和“可维护性”对我来说太宽了。谢谢塔哈的回答,+1!这里的大多数类型都没有意义。传输策略没有逻辑!要求中没有具体说明。感谢@StuPointerException提供答案,这很有帮助,+1!拥有私有字段,然后拥有这些字段的访问器方法有什么意义?一个人不需要广告