例如:
public class App {
private Car car = new Car();
public static void main(String[] args) {
// TO DO
}
}
如果不好,有什么解决办法?你将如何重写这段代码?
如果程序“总是”需要对象的实例并且创建实例的成本不太高(时间、资源),则可以在声明中初始化对象。那么是的,可能需要这种类型的“急切初始化”。
但是,这种设计在保持类松散耦合并增加单元测试难度方面确实与 OO 设计背道而驰。
在示例中:
public class App {
private Car car = new Car();
}
你是说:
理想情况下,您只想在实际需要时创建对象。或者在构造函数(默认或重载)中提供一些灵活性。
public class App {
private Car car;
App() {
}
// overloaded constructor
App(Car car) {
this.car = car;
}
public void setCar(Car car) {
this.car = car;
}
public Car getCar() {
return car;
}
public static void main(String[] args) {
// default constructor, lightweight, no car initialization happening;
App ap1 = new App();
// Ok, now I want a car, and it should be red.
Car redCar = new Car("red");
ap1.setCar(redCar);
// Using overloaded constructor, now I can control aspects of "car"
Car blueCar = new Car("blue");
App ap2 = new App(blueCar);
}
}
在我看来,一切都取决于您正在处理的应用程序的设计。对于提供的示例,我认为这是可以接受的。但对于其他更明确的数据类型,我更喜欢构造函数初始化。主要是因为构造函数重载是可能的。
我一直被教导你在上面声明并在里面初始化。在构造函数内部初始化东西更有效,因为如果您需要在构造时使用传入的参数更改它,那么您正在初始化并分配何时可以初始化。
例如:
public class TestClass{
//Declared but uninitialized
Object obj;
//Makes no difference but easier to read
public TestClass(){
this.obj = new Object();
}
//In this constructor however the object being passed in is what is initializing obj
//-so if you were to initialize it above and then change it down here you are writing
//-to the mem twice and it is less efficient.
public TestClass(Object arg){
this.obj = (Object)arg;
}
}
需要注意的是,这些天的内存真的很便宜。这样做的唯一真正目的(除了不想看起来像个菜鸟)是让它可以被其他人管理。
If you want your code to be easier to test it's a bad practice. The reason why is that creating App
will also create a Car
whether you want it or not. Now, if Car
has code that connects to a database, oops, now when you test App
you need to have a database available you can connect to or your test will fail.
The solution is Dependency Injection aka Inversion of Control. You'd write it like this:
public class App {
private Car car;
public App(Car car) {
this.car = car;
}
public static void main(String[] args) {
// TO DO
}
}
Now creating App
doesn't necessarily create a Car
and they are coupled less.
Now, I'm being very pedantic here. I probably use your example all the time in my code. I'm just pointing out a downside. This isn't ALWAYS bad and isn't ALWAYS good.
private Car car = new Car();
This perfectly ok IMHO. A couple of reasons for not doing it:
Car.<init>
requires arguments that are only available in App.init
App
has many fields and others are need to be initialized in App.<init>
and for consistency you want to keep them all together.In any case, don't do the following:
private Car car = null;
Because every java developer knows that instance fields are initialized to null
.
使用 Init() 方法进行所有初始化。
公共类应用程序{
private Car car;
public App() {
this.car = null;
}
public void Init() {
this.car = new Car();
}
public void Shutdown() {
this.car = null;
}
public static void main(String[] args) {
App app = new App();
app.Init();
app.Shutdown();
app = null;
}
}
除了 tieTYT 写的内容之外,可能值得考虑的是,如果您在构造函数中实例化所有成员,它会使其更具可读性。您需要了解的有关该类型的新对象的所有信息都可以通过阅读构造函数来了解。
请注意,以下之间的含义有所不同:
public class App {
private Car car = new Car();
public static void main(String[] args) {
// TO DO
}
}
和
public class App {
private Car car;
public App(){
car = new Car();
}
}
例如,如果 new Car() 首先失败,那么您肯定会在调试时玩得很开心。如有必要,第二个更具可读性和可调试性。如果您将字段视为类蓝图的一部分,那么在它们的声明中初始化它们就没有什么意义了。由于这里有 main,这可能是您的入口点,但对于其他类,如果您将它们视为对象的蓝图,那么构造函数的想法很有意义:
public class App{
private Car car;
public Car getCar(){
return car;
}
public void setCar(Car car){
this.car = car;
}
public App(Car car){
this.car = car;
}
}
我想,这是 oop 类最常见的结构。
执行此代码的完美方法是在 main 方法中创建一个 App 类型的 Object,该方法将调用 Car 类的构造函数。因此代码将如下所示。
公共类应用程序{
private Car car;
public static void main(String[] args)
{
App app=new App(); //
app.car. //Followed by the method or the member variable that you would like to
//access
}
}