例えば:
public class App {
private Car car = new Car();
public static void main(String[] args) {
// TO DO
}
}
良くない場合、解決策は何ですか?このコードをどのように書き換えますか?
私はいつもあなたが上で宣言して内部で初期化することを教えられてきました。コンストラクター内で初期化する方が効率的です。これは、構築時に渡されたパラメーターを使用してコンストラクターを変更する必要がある場合、初期化して、初期化できるときに割り当てるためです。
例えば:
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;
}
}
これに対する注意点は、最近のメモリは本当に安いということです。この方法でそれを行う唯一の本当の目的は(新人のように見えたくないことを除いて)、他の人がそれを管理できるようにすることです。
私の意見では、すべては作業中のアプリケーションの設計に依存します。提供された例については、許容できると思います。しかし、他のより決定的なデータ型については、コンストラクターの初期化を好みます。主な理由は、コンストラクターのオーバーロードが可能であるためです。
プログラムが「常に」オブジェクトのインスタンスを必要とし、インスタンスを作成するコストがそれほど大きくない場合 (時間、リソース)、宣言でオブジェクトを初期化することができます。そうです、このタイプの「熱心な初期化」が望ましいかもしれません。
ただし、この設計は、クラスを疎結合に保つという点で 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);
}
}
このコードを実行する完璧な方法は、メインメソッドにAppタイプのオブジェクトを作成し、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
}
}
コードのテストを簡単にしたい場合は、悪い習慣です。その理由は、作成App
すると、Car
必要かどうかに関係なく作成されるためです。さて、Car
データベースに接続するコードがある場合は、おっと、テストするときにApp
接続できるデータベースを用意する必要があります。そうしないと、テストは失敗します。
解決策は、依存性注入、別名制御の反転です。あなたはそれをこのように書くでしょう:
public class App {
private Car car;
public App(Car car) {
this.car = car;
}
public static void main(String[] args) {
// TO DO
}
}
現在、作成App
しても必ずしもが作成されるわけではなく、Car
結合も少なくなります。
今、私はここで非常に衒学者です。私はおそらくあなたの例を私のコードでいつも使っています。欠点を指摘しているだけです。これは常に悪いことではなく、常に良いことでもありません。
自家用車=newCar();
これは完全に大丈夫です。それをしない理由のいくつか:
Car.<init>
でのみ使用可能な引数が必要ですApp.init
App
多くのフィールドがあり、他のフィールドは初期化する必要がありApp.<init>
、一貫性を保つためにそれらをすべて一緒に保持する必要があります。いずれの場合も、次のことを行わないでください。
自家用車=null;
すべてのJava開発者は、インスタンスフィールドがに初期化されることを知っているから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() が失敗した場合は、それをデバッグするのが楽しくなります。2 番目は、必要に応じてはるかに読みやすく、デバッグ可能です。フィールドをクラスの設計図の一部と考えると、宣言でフィールドを初期化することはほとんど意味がありません。ここに 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 クラスの最も一般的な構造だと思います。
すべての初期化に 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;
}
}