Effective Java 1 -- 考虑用静态工厂方法代替构造器

    从今天开始,固定更新一个模块,更新Effective Java这本书介绍的一些知识点。


1、考虑用静态工厂方法代替构造器

    通常来说,获得一个类的实例的方法一般是使用构造器,但是也有其他方法,比如让这个类提供一个静态工厂方法,这个方法是一个生产该类实例的静态方法。

    静态工厂方法比起构造器方法的优点在于:

    ①、有名称,这个名称可以表名这个静态工厂方法提供的实例的特点。

    ②、不用每次调用都创建一个对象。构造器在调用的时候总会创建一个新的对象,然而创建对象在java中是有一定的开销的,使用静态工厂方法可以解决问题。静态工厂方法不一定要在这个方法内部创建新的对象,可以是先创建好对象然后通过这个工厂返回。而且静态工厂方法能供重复调用返回相同的对象,这样有助于严格控制哪个时刻哪些类应该存在。

    ③、可以返回原返回类型的任何子类型的对象,更灵活。

    ④、代码更简洁。比如对于使用构造器来进行构造:

           HashMap<String,List<String>> map = new HashMap<String,List<String>>();//这样很繁杂

           然而当使用静态工厂方法的时候,可以简化以上的代码:

           HashMap<String,List<String>> map = HashMap.newInstance();//更简洁 当然jdk中没有这么写

     静态工厂方法的主要缺点在于:

     ①、如果类不含有受保护的或者共有的构造函数,则它不能被子类化。这是它的一个主要缺点,但是也可以被视为优点,因为这个机制鼓励程序员不要去继承(extends)(is a),而是去复合(composition)(has a)。

     ②、静态工厂方法和其他静态方法没有什么表现上的差异,而不像构造器那样展现得不同。


下面用代码来展示出静态工厂方法,首先创建一个package 静态工厂,创建一个接口Provider,声明创建实例Service的方法newInstance:

package 静态工厂;

public interface Provider {
    public Service newInstance();//创建实例Service的工厂
}
然后创建一个接口Service,声明被创建实例所拥有的方法:

package 静态工厂;

public interface Service {
    //工厂生产实体的功能
    public void run();
}
创建Services类,用来提供对应工厂生产的对应实例:

package 静态工厂;

import java.util.concurrent.ConcurrentHashMap;

public class Services {
    //Services工厂中名字和生产实例的类的实例映射
    private final static ConcurrentHashMap<String,Provider> map = new ConcurrentHashMap<String,Provider>();
    private final static String DEFAULT_NAME = "default";
    
    //提供注册工厂的函数
    public static void RegisterProviders(String name , Provider p){
        map.put(name, p);//添加工厂对应的名字及工厂实例
    }
    public static void RegisterDefaultProviders(Provider p){
        RegisterProviders(DEFAULT_NAME, p);
    }
    
    //生产实例
    public static Service newInstance(String name){
        Provider p =map.get(name);//不是newInstance的时候才创建 而是实现创建好存储在map里
        if(p == null){
            throw new IllegalArgumentException("没有这样的工厂:"+name);
        }
        return p.newInstance();
    }
}

然后定义一个Provides类定义所需要的所有工厂类型:

package 静态工厂;

public class Providers {
    public static final Provider p1 = new Provider(){
        @Override
        public Service newInstance() {
            return new Service(){//返回匿名实例
                @Override
                public void run() {
                    System.out.println("This is service of P1");
                }
            };
        }
    };
    public static final Provider p2 = new Provider(){

        @Override
        public Service newInstance() {
            return new Service(){

                @Override
                public void run() {
                    System.out.println("This is service of P2");
                }
                
            };
        }
        
    };
}

最后写一个测试类,来测试工厂:

package 静态工厂;

public class Test {
    public static void main(String[] args) {
        //获取生产者
        Provider p1 = Providers.p1;
        Provider p2 = Providers.p2;

        //注册工厂
        Services.RegisterProviders("provider1",p1);
        Services.RegisterProviders("provider2",p2);
        
        //获取实例
        try {
            Service s1 = Services.newInstance("provider1");
            Service s2 = Services.newInstance("provider2");
            s1.run();
            s2.run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在需要创建实例的时候,静态工厂方法通常更加合适,因此切忌第一个感觉就是使用构造器,而不是静态工厂方法。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值