zoukankan      html  css  js  c++  java
  • Java随谈(三)如何创建好一个对象?

    本文推荐阅读时间30分钟

     (注意: 编写这篇文章的意义在于,希望自己能够在今后的编程生涯中,每一个实现,都是根据需求去思考,选择较优的实现方式(不是最优而是较优是考虑时间、实现成本等因素,具体见赫伯特西蒙的原则),而不是拿一把锤子,看什么都像钉子。)

     

    Java语法中的创建对象方式

    大家都知道,在编写Java程序里,一般就是处理各种各样的对象,那么,你知道一共有多少种创建对象的方式吗?

    希望大家能稍微思考一下再往下翻。

    答案是4种

    • new 一个对象
    • 反射一个类实例化一个对象(反射类和反射构造方法)
    • clone 一个对象
    • 反序列化一个对象

    前两者调用了构造方法,后两者没有调用。

    其中,日常使用中,最为常见的是使用new关键字创建对象;而在框架之中,最常用的是反射来控制对象生成。

     常见的几种构造对象的方式(实现角度)

    下面详细地梳理常见的创建对象、设置属性的逻辑

    1. 若编写一个新的类,此时没有任何额外的需求时,采用最简单的构造方法即可。
    2. 若对象属性很多,但其中必传属性不多,可以使用set设置属性,或者重叠构造器模式。
    3. 若对象的属性和方法的传参类似,可以使用org.springframework.beans.BeanUtils.copyProperties()方法搭配set方法来设置参数。
    4. 若对象需要有一些特殊功能,比如单例,能够缓存等,可以使用静态工厂方法。
    5. 若对象需要一次性构建(创建不可变对象),使用建造者模式。
    6. 若对象为底层资源,会被各种方法依赖,使用依赖注入。

    1.1 Java原生构造方法,和类同名即可

    public class Order {
        private String code;
        private List<String> offers;
        private Map<String, Object> features;
        public Order() {
        }
        public Order(String code, List<String> offers, Map<String, Object> features) {
            this.code = code;
            this.offers = offers;
            this.features = features;
        }
    }

    2.1 重叠构造器模式

    public class Order {
        // not null!
        private String code;
        private List<String> offers;
        private Map<String, Object> features;
        //传入code, offers设为空集合, features设为空表
        public Order(String code) {
            this(code, new ArrayList<>(), new HashMap<>());
        }
        //传入code, offers, features设为空表
        public Order(String code, List<String> offers) {
            this(code, offers, new HashMap<>());
        }
        //传入code,features,offers设为空集合
        public Order(String code, Map<String, Object> features) {
            this(code, new ArrayList<>(), features);
        }
        //传入code, offers, features
        public Order(String code, List<String> offers, Map<String, Object> features) {
            this.code = code;
            this.offers = offers;
            this.features = features;
        }
    }

    2.2 set设置属性

    public class Order {
        private String code;
        private List<String> offers;
        private Map<String, Object> features;
    
        public String getCode() {
            return code;
        }
        public void setCode(String code) {
            this.code = code;
        }
        public List<String> getOffers() {
            return offers;
        }
        public void setOffers(List<String> offers) {
            this.offers = offers;
        }
        public Map<String, Object> getFeatures() {
            return features;
        }
        public void setFeatures(Map<String, Object> features) {
            this.features = features;
        }
    }

    3.1 从传参中获取属性, 使用 org.springframework.beans.BeanUtils

    //为省略代码量,使用lombok的@Data
    
    //Order.java
    @Data
    public class Order {
        private String code;
        private List<String> offers;
        private Map<String, Object> features;
    }
    
    //FooModel.java
    //和Order.java的属性一致
    @Data
    public class FooModel {
        private String code;
        private List<String> offers;
        private Map<String, Object> features;
    }
    
    //FooTest.class
    
    import org.springframework.beans.BeanUtils;
    
    public class FooTest {
        public void handleFoo(FooModel model) {
            Order order = new Order();
            BeanUtils.copyProperties(model, order);
            //处理order对象
        }
    }

    4.1 静态工厂方法之单例对象(一)

    /**
     * 枚举来创建单例对象有以下优势
     * 1.构造方法已私有化
     * 2.是否多线程安全
     * 3.支持序列化机制,防止多次序列化创建对象
     */
    public enum Singleton {
        INSTANCE;
        public void method() {
        //函数处理
        }
    }

    4.1 静态工厂方法之单例对象(二)

    /**
     * 静态内部类来创建单例模式有以下优势
     * 1.代码实现简单
     * 2.无需处理多线程问题(类初始化时会先进行静态代码的创建)
     * 3.属于懒汉式,不使用时不占用空间
     */
    public class Singleton {
        //私有化构造器
        private Singleton() {
        }
        //静态内部类
        private static class StaticInnerClass {
            private static final Singleton instance = new Singleton();
        }
        //对外的静态工厂方法
        public static SingletonPattern getInstance() {
            return StaticInnerClass.instance;
        }
    }

    4.2 静态工厂方法之缓存对象

    /**
     * 下面以经典的Boolean.java来举例
     * Boolean类创建了两个常量属性,TRUE和FALSE
     * 在调用valueOf时使用这个缓存
     */
    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);
    
        private final boolean value;
    
        public Boolean(boolean value) {
            this.value = value;
        }
    
        //返回缓存值,不新创建对象
        public static Boolean valueOf(boolean b) {
            return (b ? TRUE : FALSE);
        }
    }

    4.2 静态工厂方法之缓存对象 (二)

        /**
         * IntegerCache 缓存了-128到127的数字
         */
        public static Integer valueOf(int i) {
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }

    5.1 Java8之前建造者模式(不依赖第三方库)

    public class Order {
        private String code;
        private List<String> offers;
        private Map<String, Object> features;
        
        public static Builder builder() {
            return new Builder();
        }
        //私有化构造方法,只提供给Builder.build()使用
        private Order(String code, List<String> offers, Map<String, Object> features) {
            this.code = code;
            this.offers = offers;
            this.features = features;
        }
    
        public String toString() {
            return "Order(code=" + this.code + ", offers=" + this.offers + ", features=" + this.features + ")";
        }
        
        public static class Builder {
            private String code;
            private List<String> offers;
            private Map<String, Object> features;
    
            public Builder code(String code) {
                this.code = code;
                return this;
            }
            public Builder offers(List<String> offers) {
                this.offers = offers;
                return this;
            }
            public Builder offer(String offer) {
                if (null == this.offers) {
                    this.offers = new ArrayList<>();
                }
                this.offers.add(offer);
                return this;
            }
            public Builder features(Map<String, Object> features) {
                this.features = features;
                return this;
            }
            public Builder feature(String key, Object value) {
                if (null == this.features) {
                    this.features = new HashMap<>();
                }
                this.features.put(key, value);
                return this;
            }
            public Order build() {
                return new Order(this.code, this.offers, this.features);
            }
        }
    
            public static void main(String[] args) {
            Order order = Order.builder()
                    .code("1234")
                    .offer("满100减5")
                    .offer("满200减15")
                    .feature("color", "white")
                    .feature("category", "shirt")
                    .build();
            System.out.println(order);
        }
    }
    
    /** 输出
    Order(code=1234, offers=[满100减5, 满200减15], features={color=white, category=shirt})
    
    Process finished with exit code 0
    */

    5.2 Java8建造者模式(不依赖第三方库)

    函数式接口和泛型建造者模式

    @FunctionalInterface
    public interface KeyValueConsumer<T, K, V> {
    
        void accept(T t, K k, V v);
    
        default KeyValueConsumer<T, K, V> andThen(KeyValueConsumer<? super T, ? super K, ? super V> after) {
            Objects.requireNonNull(after);
            return (t, k, v) -> {
                accept(t, k, v);
                after.accept(t, k, v);
            };
        }
    }
    
    
    public class GenericBuilder<T> {
        private final Supplier<T> instantiator;
        private List<Consumer<T>> instantiatorModifiers = new ArrayList<>();
        private List<Consumer<T>> keyValueModifiers = new ArrayList<>();
        public GenericBuilder(Supplier<T> instantiator) {
            this.instantiator = instantiator;
        }
        public static <T> GenericBuilder<T> of(Supplier<T> instantiator) {
            return new GenericBuilder<T>(instantiator);
        }
        public <U> GenericBuilder<T> with(BiConsumer<T, U> consumer, U value) {
            Consumer<T> c = instance -> consumer.accept(instance, value);
            instantiatorModifiers.add(c);
            return this;
        }
        public <K, V> GenericBuilder<T> with(KeyValueConsumer<T, K, V> consumer, K key, V value) {
            Consumer<T> c = instance -> consumer.accept(instance, key, value);
            keyValueModifiers.add(c);
            return this;
        }
        public T build() {
            T value = instantiator.get();
            instantiatorModifiers.forEach(modifier -> modifier.accept(value));
            keyValueModifiers.forEach(keyValueModifier -> keyValueModifier.accept(value));
            instantiatorModifiers.clear();
            keyValueModifiers.clear();
            return value;
        }
    }

    实际操作类

    package com.example.demo.bean;
    
    import lombok.Builder;
    import lombok.Singular;
    import lombok.ToString;
    
    import java.util.*;
    
    public class Order {
        private String code;
        private List<String> offers;
        private Map<String, Object> features;
    
        //省略无参构造方法,set、get,toString方法
    
        public void addOffer(String offer) {
            offers = Optional.ofNullable(offers)
                    .orElseGet(ArrayList::new);
            offers.add(offer);
        }
    
        public <T> void addFeature(String key, T value) {
            features = Optional.ofNullable(features)
                    .orElseGet(HashMap::new);
            features.put(key, value);
        }
    
        public static void main(String[] args) {
            Order order = GenericBuilder.of(Order::new)
                    .with(Order::setCode, "1234")
                    .with(Order::addOffer, "满200减15")
                    .with(Order::addOffer, "满200减15")
                    .with(Order::addFeature, "color", "white")
                    .with(Order::addFeature, "category", "shirt").build();
            System.out.println(order);
        }
    }
    
    /** 输出
    Order(code=1234, offers=[满200减15, 满200减15], features={color=white, category=shirt})
    
    Process finished with exit code 0
    */

    5.3 lombok第三方库的建造者模式

    @ToString
    @Builder
    public class Order {
        private String code;
        @Singular
        private List<String> offers;
        @Singular
        private Map<String, Object> features;
    
        public static void main(String[] args) {
            Order order = Order.builder()
                    .code("1234")
                    .offer("满100减5")
                    .offer("满200减15")
                    .feature("color", "white")
                    .feature("category", "shirt")
                    .build();
            System.out.println(order);
        }
    }
    
    /** 输出
    Order(code=1234, offers=[满200减15, 满200减15], features={color=white, category=shirt})
    
    Process finished with exit code 0
    */

    6.1 依赖注入

    为了减少无关代码量,这里不展示Spring boot的配置文件,只展示实际的操作代码

    @RestController
    public class DemoController {
        //自动注入demoService,程序员不用关心对象何时创建
        @Autowired
        private DemoService demoService;
    
        @GetMapping
        public String getDemo() {
            return demoService.get();
        }

    建造者模式来源于 如何实现Builder模式

    单例模式来源于 Effective Java

  • 相关阅读:
    时间格式
    分页1
    vs2010 VS2008 VS2005 快捷键大全
    css 常用标签
    JS Array数组操作
    CSS属性
    jquery 选择器大全
    @fontface
    以前写过的ajax基础案例(王欢huanhuan)
    Jquery操作下拉框(DropDownList)的取值赋值实现代码(王欢)
  • 原文地址:https://www.cnblogs.com/kwanwoo/p/13725632.html
Copyright © 2011-2022 走看看