Search code examples
javaoopdesign-patternsadapter

Hide third party class's java.util.date behind adapter pattern? (wrapper)


Is this considered adapter pattern? Is this a valid use case? Is it a good implementation?

// cannot change this class
public class ProductExample {
  private Date createDate;

  private Integer id;

  public Date getCreateDate() {
    return createDate;
  }

  public Integer getId() {
    return id;
  }

}

public class ProductExampleAdapter {

  private final ProductExample productExample;

  public ProductExampleAdapter(ProductExample productExample) {
    this.productExample = productExample;
  }

  public LocalDate getCreateDate() {
    return productExample.getCreateDate().toInstant()
            .atZone(ZoneId.systemDefault())
            .toLocalDate();
  }

  public Integer getId() {
    return productExample.getId();
  }

}

I'm just trying to hide the old java.util.Date API and use the new LocalDate instead in my code.


Solution

  • As wiki says:

    the adapter pattern is a software design pattern (also known as wrapper, an alternative naming shared with the decorator pattern) that allows the interface of an existing class to be used as another interface.1 It is often used to make existing classes work with others without modifying their source code.

    yeah, this is Adapter pattern in action. Why? As you adapted your method getCreateDate to return LocalDate type.

    One thing should be considered that both classes should share some abstraction like Abstract class or interface. It is necessary to be interchangeable. Let me show an example.

    We need some abstraction like interface:

    public interface IProduct
    {
        public LocalDate getCreateDate();
    
        public int getId();
    }
    

    And Product class:

    public class Product : IProduct
    {
        public LocalDate getCreateDate()
        {
            throw new NotImplementedException();
        }
    
        public int getId()
        {
            throw new NotImplementedException();
        }
    }
    

    And:

    public class ProductExampleAdapter : IProduct // "implements" in Java
    {
    
        private final ProductExample productExample;
    
        public ProductExampleAdapter(ProductExample productExample) {
            this.productExample = productExample;
        }
    
        public LocalDate getCreateDate() {
            return productExample.getCreateDate().toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDate();
        }
    
        public Integer getId() {
            return productExample.getId();
        }
    }
    
    public class ProductExample {
    
    }
    

    And then it can be used like this:

    List<IProduct> products = new List<IProduct>();
    products.Add(new Product());
    products.Add(new ProductExampleAdapter(new ProductExample()));