EffectiveJava----静态工厂方法(我认为应该叫静态构造器方法)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shentanweilan9/article/details/80693592

一个模块的使用者永远也不应该被模块的行为所迷惑(那样就不清晰了),模块要尽可能的小,但又不能太小【术语模块(module):是指任何可重用的软件组件,从单个方法到包含多个包的复杂系统都可以是一个模块】。代码应该被重用,而不是拷贝,模块之间的相依性应该尽可能降低到最小,错误应该尽早被检测出来,理想的情况下是在编译的时刻。

1.用静态工厂方法代替构造器(构造函数)
  1. 静态工厂方法与设计模式中的工厂模式是不同的。
    • 静态工厂方法是获取这个类自身的一个实例,他的存在是为了更好的描述和处理这个类
    • 工厂模式的作用更在于解耦,让每个类在实例化的时候不再使用new这种耦合度极高的方法。
    • 静态工厂方法只是一个“普通的方法”(返回这个对象的一个实例这种特点的静态方法)
    • 工厂方法又分为三种模式:简单工厂模式、工厂模式(工厂方法模式)、抽象工厂模式。这三种是为了一个目标的不同程度的抽象。工厂方法用一种比静态工厂方法更加系统的理论来对每一个需要使用的对象进行包装这种包装下再也不使用new来创建对象,随着抽象程度的变高,我们甚至可以将这种创建对象放到xml或者注释之中,就比如一些框架。
    • 静态工厂方法在一个类的内部,较小的范围里可以让你创建对象更加方便优雅,而工厂模式在大的范围中能够让你的代码重用性更佳,耦合度更低。
  2. 静态工厂方法与构造器最大的不同 在于它有名称。使用静态工厂方法,为不同的构造方法来起不同的名字来区分不同功能的实例化,而返回的都是一个this。
    • 比如 valueOf、newInstance、getInstance 等,对于代码的编写和阅读都能够更清晰。 Calendar.getInstance(); Integer.valueOf(“3”);
    • 而不是new 各种构造器
  3. 静态工厂方法可以返回一个现有的实例。
    • 我们使用new来初始化一个对象时,都无疑是在堆上创建了一个新的对象
    • 有些不可变的类、不希望被实例出多个对象的类不用也不必每次都创建一个对象。通过静态工厂方法,我们可以直接向客户端返回一个我们早已创建好的对象,对于有些不可变的类,比如基本类型包装类,这样做可以极大地节省我们的开销。
  4. 静态工厂方法可以返回原返回类型的任何子类型的对象。(通过返回一个List(或者其他具体类型的祖先类,Set,Map等)对象,让那些List的子类都可以来调用这个方法。)

    Class Person {
        public static Person getInstance(){
            return new Person();
            // 这里可以改为 return new Player() / Cooker()
        }
    }
    Class Player extends Person{
    }
    Class Cooker extends Person{
    }
    
  5. 可以有多个参数相同但名称不同的工厂方法

    class Child{
            int age = 10;
            int weight = 30;
            public static Child newChild(int age, int weight) {
                Child child = new Child();
                child.weight = weight;
                child.age = age;
                return child;
            }
            //  完美解决了  构造函数 重载无法解决的问题。
            public static Child newChildWithWeight(int weight) {
                Child child = new Child();
                child.weight = weight;
                return child;
            }
            public static Child newChildWithAge(int age) {
                Child child = new Child();
                child.age = age;
                return child;
            }
        }
    
  6. 可以减少对外暴露的属性

    class Player {
        public static final int TYPE_RUNNER = 1;
        public static final int TYPE_SWIMMER = 2;
        public static final int TYPE_RACER = 3;
        int type;
    
        private Player(int type) {
            this.type = type;
        }
    
        public static Player newRunner() {
            return new Player(TYPE_RUNNER);
        }
        public static Player newSwimmer() {
            return new Player(TYPE_SWIMMER);
        }
        public static Player newRacer() {
            return new Player(TYPE_RACER);
        }
    }
    
  7. 多了一层控制,方便统一修改尽量封装起来 是代码看的更简洁,看个人习惯问题 对于可能被多个地方引用的类和对象 封装是为了更好的扩展 因为封装起来后 以后改动只需要改一个地方。

     class User{
            String name ;
            int age ;
            String description;
            public static User newTestInstance() {
                User tester = new User();
                tester.setName("隔壁老张");
                tester.setAge(16);
                tester.setDescription("我住隔壁我姓张!");
                return tester;
            }
        }
        // 创建一个测试数据
        User tester = User.newTestInstance();
    
2. 工厂模式
  1. 简单工厂 工厂类中,根据条件决定一个接口由哪个具体产品类来实现。注意简单工厂 和上面的静态工厂方法不一样 其实我认为上面不应该叫静态工厂方法 应该叫静态构造器方法(通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类)
  2. 工厂方法 创建多个工厂类。各个工厂类中,都对应一个获得接口A实例的方法。用户决定使用哪个工厂。工厂方法将类的实例化推迟到了其子类。所以使用工厂方法模式时,需要客户端决定实例化哪一个工厂类。选择判断问题还是存在的。也就是说,工厂方法把简单的工厂内部逻辑判断转移到了客户端来运行。你想要加的功能,本来是要改工厂类的,而现在是修改客户端。不过,我们在某些情况下通过工厂方法,只需要修改一行实例化的代码就可以实现系统元素的切换(比如切换数据源)。这也是很方便的。
  3. 抽象工厂:对工厂方法进行扩展。各个工厂类中,再增加一个获得接口B实例的方法。抽象工厂为不同产品族的对象创建提供接口。使用场景系统需要在不同产品族进行切换
    • 抽象工厂最大的好处就是便于交换产品系列,具体工厂在代码中一般只出现一次。这就使得改变应用的具体工厂很容易。
    • 第二个好处是他能让具体的创建对象实例和客户端分离,客户端是通过他们的抽象接口操作实例
    • 抽象工厂不太易于拓展,如果需要自增功能,或者自增产品,则需要至少修改三个类,而且实例化的代码是写死在程序中的 , 这样无法避免违背开放-关闭原则。
    • 对于上述问题,可以通过配置文件,结合反射的方式来解决
  4. 工厂类可以继承于某个接口,或是抽象类,工厂类已经对产品类的实现就行了封装,用户用它结合配置参数和反射实现动态创建,是很合理的。相比简单工厂是不太合适的。
  5. 代码底层,当产品类创建分支是固定或是其他类似的地方很少时,用简单工厂很合适。因为一旦增加分支,改的地方很少。如果不是,建议用工厂方法。
  6. 抽象工厂和工厂方法没有本质区别,是对工厂方法的扩展。当产品类,涉及到多个产品簇时,需要对同类的产品抽象为一个接口。工厂类中,可以定义多个返回具体产品的方法,自由组合。

简单工厂

    public abstract class Operation {

        public abstract float getResult(float firstNumber, float secondNumber);

    }
    //把符号都当做对象处理,实现此接口
    public class AddOperation extends Operation {
        @Override
        public float getResult(float firstNumber, float secondNumber) {
            return firstNumber+secondNumber;
        }

    }
    public class SubOperation extends Operation {
        @Override
        public float getResult(float firstNumber, float secondNumber) {
            return firstNumber-secondNumber;
        }
    }
    public class MulOperation extends Operation {
        @Override
        public float getResult(float firstNumber, float secondNumber) {
            return firstNumber*secondNumber;
        }
    }
    public class DivOperation extends Operation {
        @Override
        public float getResult(float firstNumber, float secondNumber) {
            return firstNumber/secondNumber;
        }
    }

    //接下来需要解决的就是对象的创建问题了,既如何根据不同的情况创建不同的对象:我们正好可以通过简单工厂模式实现
    public class OperationFactory {

        public static Operation getOperation(String quotaFlag){
            Operation o = null;
            switch (quotaFlag){
                case "+" :  o = new AddOperation();
                case "-" :  o = new SubOperation();
                case "*" :  o = new MulOperation();
                case "/" :  o = new DivOperation();
                default:break;
            }
            return o;
        }
    }
    //调用:
    public class Computer {
        public static void main(String[] args) {
            Scanner in = new Scanner(System.in);
            System.out.println("请输入第一个数字:");
            float firstNum  = in.nextFloat();
            System.out.println("请输入第二个数字:");
            float secondNum  = in.nextFloat();
            System.out.println("请输入运算符号:");
            String countQuato = in.next();
            System.out.println(count(firstNum,secondNum,countQuato));
        }
        private static float count(float firstNum,float secondNum , String countQuota){
        //通过工厂类获取对象
            Operation operation = OperationFactory.getOperation(countQuota);
            return operation.getResult(firstNum,secondNum);
        }
    }

工厂

    //定义上级工厂的接口
    public interface IFractory {
        public Operation generateOper();
    }
    //为每一个类创建工厂
    /**
     * 工厂方法  为每个对象生成一个工厂类
     */
    public class AddOperationFactory implements IFractory{

        @Override
        public Operation generateOper() {
            return new AddOperation();
        }
    }
    public class SubOperationFactory implements IFractory {
        @Override
        public Operation generateOper() {
            return new SubOperation();
        }
    }
    public class MulOperationFactory implements IFractory {
        @Override
        public Operation generateOper() {
            return new MulOperation();
        }
    }
    public class DivOperationFactory implements IFractory {
        @Override
        public Operation generateOper() {
            return new DivOperation();
        }
    }
    //客户端代码
    IFractory fractory = new AddOperationFactory();
    Operation operation = fractory.generateOper();
    operation.getResult(firstNum,secondNum);

抽象工厂

        public interface IFacfory {
            public IUser createUser();
            public IDepartment createDepartment();
        }
        public interface IUser {
            public void insert();
            public void getById();
        }
        public interface IDepartment {
            public void insert();
            public void getDepartmentById();
        }
        public class SqlServerUser implements IUser {
            @Override
            public void insert() {
                System.out.println("insert into sqlserver.");
            }

            @Override
            public void getById() {
                System.out.println("get user by id from sqlserver.");
            }
        }
        public class SqlServerDepartment implements IDepartment {
            @Override
            public void insert() {
                System.out.println("insert department into sqlserver.");
            }

            @Override
            public void getDepartmentById() {
                System.out.println("get department in sqlserver by id.");
            }
        }

        public class AccessUser implements IUser {
            @Override
            public void insert() {
                System.out.println("insert into access");
            }

            @Override
            public void getById() {
                System.out.println("get by id from access");
            }
        }
        public class AccessDepartment implements IDepartment {
            @Override
            public void insert() {
                System.out.println("insert department into sqlserver.");
            }

            @Override
            public void getDepartmentById() {
                System.out.println("get department in sqlserver by id.");
            }
        }

        //不同产品组使用一个工厂
        public class SqlServerFactory implements IFacfory {
            @Override
            public IUser createUser() {
                return new SqlServerUser();
            }

            @Override
            public IDepartment createDepartment() {
                return new SqlServerDepartment();
            }
        }
        public class AccessFactory implements IFacfory {
            @Override
            public IUser createUser() {
                return new AccessUser();
            }

            @Override
            public IDepartment createDepartment() {
                return new AccessDepartment();
            }
        }
        客户端:
        IFacfory facfory = new AccessFactory();
        IUser user = facfory.createUser();
        IDepartment department = facfory.createDepartment();
        user.insert();
        user.getById();
        department.insert();
        department.getDepartmentById();
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页