Scala工厂模式下如何为私有实现类添加独有方法
子类独有方法无法调用的本质是静态类型检查限制:你定义的Car.apply方法返回值类型声明为抽象类Car,编译器在编译阶段只会校验Car类中声明过的成员,和运行时对象的实际类型无关——只要方法没有在Car中定义,就会直接报编译错误,这个问题和子类是否私有没有直接关系,哪怕子类是public的,只要变量声明为父类类型,同样无法直接调用子类独有方法。
另外你贴的原始代码有两处不规范/错误点:
- 类名
standardCar首字母小写,不符合Scala编码规范,类名应统一使用大驼峰命名 - 伴生对象中定义的车型常量
STANDARD=0/DELUXE=1/LUXURY=2和apply方法的case分支对应关系错误,当前调用Car(1)实际返回的是LuxuryCar实例,和常量定义不一致,使用时会出现逻辑错误。
按照推荐优先级从高到低排列,可根据业务场景选择:
方案1:将独有能力封装进父类通用方法(最符合工厂模式设计原则)
工厂模式的核心是对外隐藏实现细节,所有交互都基于父类抽象完成。如果不需要外部感知车型差异,只是不同车型有不同的特殊逻辑,完全不需要暴露子类的独有方法,直接在父类中定义通用抽象方法,子类重写时内部调用自己的独有逻辑即可。
代码示例:
abstract class Car{ def bookingPrice : Double def Brands : List[String] def availability : Int def book(noOfCars:Int): Unit // 新增通用特殊功能触发方法 def activateSpecialFeature(): Unit } object Car{ val STANDARD = 0 val DELUXE = 1 val LUXURY = 2 private class StandardCar extends Car{ private var _availability = 100 override def bookingPrice = 200000 override def Brands = List("Maruti", "Tata", "Hyundai") override def availability = _availability override def book(noOfCars:Int) = _availability -= noOfCars // 普通车无特殊功能,空实现即可 override def activateSpecialFeature(): Unit = println("No special feature for standard car") } private class DeluxeCar extends Car{ private var _availability = 50 override def bookingPrice = 500000 override def Brands = List("Honda", "Mahindra", "Chevrolet") override def availability = _availability override def book(noOfCars:Int) = _availability -= noOfCars // 独有私有方法 private def openSlidingDoors(): Unit = println("Sliding doors opened") // 重写通用方法,内部调用独有逻辑 override def activateSpecialFeature(): Unit = openSlidingDoors() } private class LuxuryCar extends Car{ private var _availability = 5 override def bookingPrice = 900000 override def Brands = List("Audi","BMW", "Mercedes") override def availability = _availability override def book(noOfCars:Int) = _availability -= noOfCars // 独有私有方法 private def enableFlight(): Unit = println("Flight mode enabled") // 重写通用方法,内部调用独有逻辑 override def activateSpecialFeature(): Unit = enableFlight() } // 修正分支对应关系 def apply(carType:Int):Car = carType match { case STANDARD => new StandardCar() case DELUXE => new DeluxeCar() case LUXURY => new LuxuryCar() case _ => new StandardCar() } } object Main{ def main(args: Array[String]): Unit = { val car = Car(Car.LUXURY) println(car.bookingPrice) println(car.availability) // 直接调用父类通用方法,自动匹配对应车型的特殊逻辑 car.activateSpecialFeature() } }
这种写法完全不需要修改子类的访问权限,封装性最好,外部代码不需要感知任何子类实现细节,后续新增车型只要重写对应方法即可,不需要修改外部调用逻辑。
方案2:模式匹配做安全类型转换(需要外部感知车型时使用)
如果业务逻辑确实需要根据车型做不同处理,可使用Scala原生的类型匹配做安全的类型转换,不需要放开子类的私有访问权限(如果需要外部匹配类名,将子类改为sealed密封类即可,密封类只能在当前文件内被继承,不会破坏封装,还能让编译器检查匹配分支是否完整)。
代码示例:
// 将父类改为sealed,子类保持私有即可 sealed abstract class Car{ // 成员定义不变 } // Main方法中调用 val car = Car(Car.DELUXE) car match { case c: Car.LuxuryCar => // 匹配成功后编译器会自动将c的类型推断为LuxuryCar,可直接调用独有方法 c.enableFlight() case c: Car.DeluxeCar => c.openSlidingDoors() case _ => println("standard car") }
这种写法比Java风格的强制类型转换asInstanceOf安全得多,如果类型不匹配不会直接抛出类型转换异常,会走默认分支逻辑。
方案3:提供返回具体类型的独立工厂方法
如果明确某些场景下需要直接获取指定类型的车型实例,不需要走统一的int参数入口,可以在伴生对象中新增返回具体子类类型的工厂方法,调用方拿到实例后静态类型就是对应子类,可直接调用独有方法。
代码示例:
object Car{ // 其他代码不变 def getLuxuryCar(): LuxuryCar = new LuxuryCar() def getDeluxeCar(): DeluxeCar = new DeluxeCar() } // 调用处 val luxuryCar = Car.getLuxuryCar() luxuryCar.enableFlight() // 直接调用,无需类型转换
方案4:细化特质抽象层(适合能力可复用的场景)
如果某类特殊能力不是单个车型独有,后续可能有多个车型具备相同能力,可以通过特质(trait)抽取能力层,让对应子类混入对应的能力特质,后续扩展时只要混入特质即可具备对应能力,不需要修改匹配逻辑。
代码示例:
sealed abstract class Car { // 基础成员不变 } // 抽取通用能力特质 trait SlidingDoorCapable { def openSlidingDoors(): Unit } trait FlightCapable { def enableFlight(): Unit } // 对应子类混入特质 private class DeluxeCar extends Car with SlidingDoorCapable { override def openSlidingDoors(): Unit = println("Sliding doors opened") // 其他逻辑不变 } private class LuxuryCar extends Car with FlightCapable { override def enableFlight(): Unit = println("Flight mode enabled") // 其他逻辑不变 } // 后续新增车型如果有飞行能力,直接混入FlightCapable即可 private class SuperCar extends Car with FlightCapable { override def enableFlight(): Unit = println("Super flight mode") } // 调用时直接按特质匹配,不需要关心具体车型 car match { case c: FlightCapable => c.enableFlight() case c: SlidingDoorCapable => c.openSlidingDoors() case _ => // 普通车无特殊能力 }
内容的提问来源于stack exchange,提问作者FrenchFryKid

