Effecitive javaプロジェクト1:ジェネレータではなく静的メソッドを考慮


ジェネレータではなく静的パラメータ法を考慮する
コンストラクション関数、静的パラメータメソッドの比較
共通点
  • 希望する相手を伝える
  • 差異
  • オブジェクトを作成するには、ジェネレータを介して必要なオブジェクト
  • を受信します.
  • しかし、静的ファクトリ法において、静的方法から所望のオブジェクトを取得する方法は
  • である.
    静的工場法の利点
    1.名前を付けてもいいです.
    名利
  • 生成者と異なり,メソッド名を指定することで,オブジェクトの特性を容易に理解できる.
  • デフォルトのジェネレータが使用されていると仮定
    public class Enroll {
        private String studentName;
        private int studentId;
    
        public Enroll(String studentName) {
            this.studentName = studentName;
        }
    
        public Enroll(int studentId) {
            this.studentId = studentId;
        }
    
        public static void main(String[] args) {
            Enroll enroll = new Enroll("CHOONSIK");
        }
    }
    Enrollオブジェクトが作成されています.parameterが含まれているかどうかを判断するには、ジェネレータコードを検索する必要があります.これは不便です.
    デフォルトでは、ジェネレータは同じ名前です.
    この問題は静的工場法で解決できる.
    public class Enroll {
        private String studentName;
        private int studentId;
    
        public Enroll(String studentName) {
            this.studentName = studentName;
        }
        public Enroll(int studentId) {
            this.studentId = studentId;
        }
         public static Enroll withStudentName(String studentName) {
             return new Enroll(studentName);
        }
    
        public static void main(String[] args) {
            Enroll enroll = withStudentName("CHOONSIK");
        }
    }
    
    静的メソッドにより詳細なメソッド名が与えられた.
    ソースコードを探してジェネレータコードを確認しなくても,その意味の表現がより適切であることを確認できる.
    コンストラクション関数に比べて、名前を指定できるメリットがあります.
    public class Enroll {
        private String studentName;
        private String studentNickName; <---- 새로 추가 
        private int studentId;
    
        public Enroll(String studentName) {
            this.studentName = studentName;
        }
        public Enroll(String studentNickName) {   <------ 오류 발생
            this.studentName = studentNickName;
        }
        
        public Enroll(int studentId) {
            this.studentId = studentId;
        }
         public static Enroll withStudentName(String studentName) {
             return new Enroll(studentName);
        }
    
        public static void main(String[] args) {
            Enroll enroll = withStudentName("CHOONSIK");
        }
    }
    上記のコードでは、String typeのパラメータがstudentNameのジェネレータが既に存在する.
    したがって、パラメータがString typeの別のstudentNickNameジェネレータを作成すると、エラーが発生します.
    この場合、名前を指定できるため、정적 팩터리 메소드を解析することができる.
    public class Enroll {
        private String studentName;
        private String studentNickName; <---- 새로 추가 
        private int studentId;
    
        public Enroll(String studentName) {
            this.studentName = studentName;
        }
        
        public Enroll(int studentId) {
            this.studentId = studentId;
        }
         public static Enroll withStudentName(String studentName) {
             return new Enroll(studentName);
        }
    
        public static Enroll withStudentNickName(String studentNickName){
            return new Enroll(studentNickName);
        }
        
        public static void main(String[] args) {
            Enroll enroll = withStudentNickName("Sean");
        }
    }
    2.呼び出しのたびにインスタンスを再作成する必要はありません.
    不変クラスは、インスタンスを事前に作成したり、新しく作成したインスタンスをキャッシュしたりすることで、不要なオブジェクトの作成を回避します.
    代表的な例はBooleanですvalueOf(boolean)メソッドではオブジェクトは作成されません.
    したがって、オブジェクトの作成コストが高いオブジェクトが常に要求される場合、パフォーマンスが大幅に向上します.
    public final class Boolean implements java.io.Serializable,Comparable<Boolean> {
    
        public static final Boolean TRUE = new Boolean(true);
    
        public static final Boolean FALSE = new Boolean(false);
    
        public static Boolean valueOf(boolean b) {
            return (b ? TRUE : FALSE);
        }
    }
    これにより、新しいオブジェクトは作成されず、既存のBoolean TRUE = new Boolean(true)の1つのオブジェクトがユーザに送信される.
    シングルループモードを維持し、パフォーマンスを向上させます.
    3.戻りタイプのサブタイプオブジェクトを持つ機能.
    4.入力された列挙変数に基づいて、毎回異なるオブジェクトを返すことができます.
    二つが似ているようでしたら、一気に整理しておきました.
        public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
            Enum<?>[] universe = getUniverse(elementType);
            if (universe == null)
                throw new ClassCastException(elementType + " not an enum");
    
            if (universe.length <= 64)
                return new RegularEnumSet<>(elementType, universe);
            else
                return new JumboEnumSet<>(elementType, universe);
        }
    noneOfという静的ファクトリメソッドを呼び出すと、Enum<?>[] universe = getUniverse(elementType)の宇宙の長さ(入力列挙変数に基づいて)に基づいてEnumsetのサブタイプオブジェクトが返されます.
    クライアントは、ファクトリが提供するオブジェクトがどのクラスのインスタンス(オブジェクト)であるかを知らず、知る必要もありません.
    EnumのサブクラスであればOKです.
    5.スタティックファクトリメソッドを作成するときに、返すオブジェクトクラスが存在する必要はありません.
    これは私が最も理解していないことの一つです.(私の理解に基づいて作成)
    public static Foo getFoo(){
         Foo foo = new Foo();
         foo = Class.forName("어느경로").newInstance() // foo를 상속받은 객체의 파일 경로
    	return foo;
    }
    想像してみてください.getFooという方法でfoo継承のオブジェクトを受信して渡します.
    これにより、継承されたオブジェクトが何であれ、ファイルパスのインスタンスが受信されます.
    要するに、メソッドを実行すると、ファイル(クラス)から依存オブジェクトが取得され、返されます.
    この場合、getFooを呼び出すと、ファイルに依存するためクラスが存在しない可能性があります.
    本の中でjdbcを例に挙げます.
    dbにはmysql、oracleの種類がたくさんありますが、connectionをする場合は、通常mysqlや接続情報を接続情報に入れるべきですが、どのデータベースに接続されている値にも渡されません.
    理由は授業ですforName(パス)が含まれている場合、そのパスのクラスはメモリにロードされます.
    ロード時に静的セクションが実行されるため、そのパスのdriverが登録されます.
    戻ると、静的ファクトリメソッドを作成するときに戻るオブジェクトのないクライス、すなわち、パス内の対応するファイルで実装されていない場合は、次の接続からドライバオブジェクトにアクセスしない限りエラーは発生しません.
    したがって,後でその経路を実現するクラスは関係ない.私はそう理解しています.
    public static void main(String[] args) {
    	String driverName = "com.mysql.jdbc.Driver";
    	String url = "jdbc:mysql://localhost:3306/test";
    	String user = "root";
    	String password = "root";
        
    	try {
    		Class.forName(driverName);
    
    		Connection connection = DriverManager.getConnection(url, user, password);
    
    	} catch (ClassNotFoundException e) {
    		e.printStackTrace();
    	} catch (SQLException e) {
    		e.printStackTrace();
    	}
    }
    静的アプローチの欠点
    1.共通または保護が必要な作成者を継承し、静的メソッドのみではサブクラスを作成できません.
    フレームワーク内のユーティリティ実装クラスは継承できません.
    継承にpublicprotectedの生成を必要とする者.
    たとえば、Collectionsクラスでは、作成者のアクセス制御者はprivateです.したがって、これらのクラスは誰かの親になることはできません.
    2.プログラマーは静的な方法を見つけるのが難しい.
    ジェネレータの場合、javadocはapiドキュメントとして整理して表示しますが、静的ファクトリメソッドはそうではありません.
    したがって、クラスまたはインスタンスの上部にプロシージャ・ライブラリ・メソッドに関するドキュメントを提供することが望ましい.
    間違ったところを指摘してください.ありがとうございます.