Search code examples
javainterfacecomposition

Java: Limit access to methods of a composite class (Interface and Composition)


@Getter
public abstract class BaseProduct {
    Account account = new Account();
}

public class ProductOne extends BaseProduct {
    FieldOne fieldOne = new FieldOne();
}

public class ProductTwo extends BaseProduct {
    FieldTwo fieldTwo = new FieldTwo();
}

public class Account {
    public TypeOne methodOne() {
        return typeOne;
    }

    public TypeTwo methodTwo() {
        return typeTwo;
    }
}

public class MyClass {

    ProductOne productOne = new ProductOne();
    productOne.getAccount().methodOne();    //accessible
    productOne.getAccount().methodTwo();    //not accessible (error)

    ProductTwo productTwo = new ProductTwo();
    productTwo.getAccount().methodOne();    //not accessible (error)
    productTwo.getAccount().methodTwo();    //accessible
}

So, I have two classes (ProductOne and ProductTwo) which inherits from a Base Abstract class(BaseProduct). The Base Abstract class in turns creates an object of another class (Account)

Now i want to restrict access to some methods of Account class for ProductOne objects and similarly restrict access for some other methods for ProductTwo objects.

I think I need to create Account class as an Interface/Abstract class and create different implementations for it. Is this understanding correct? Can you please show me how to do that exactly?


Solution

  • It seems you have two lines of Product concepts here. What you can do is make both BaseProduct and Account abstract and use generics.

    public abstract class BaseProduct<A extends Account> {
        public abstract A getAccount();
    }
    
    class ProductOne extends BaseProduct<TypeOneAccount> {
        FieldOne fieldOne = new FieldOne();
    }
    
    class ProductTwo extends BaseProduct<TypeTwoAccount> {
        FieldTwo fieldTwo = new FieldTwo();
    }
    

    This will allow concrete "product" types to be bound to specific Account types.

    Then, remove methodOne and methodTwo from Account and have them implemented in actual "type one" and "type two" classes:

    public abstract class Account {
    }
    
    public class TypeOneAccount extends Account {
        public TypeOne methodOne() {
            return typeOne;
        }
    }
    
    public class TypeTwoAccount extends Account {
        public TypeTwo methodTwo() {
            return typeTwo;
        }
    }
    

    With this, both of the following will fail at compile time:

    //fails because productOne.getAccount() returns a TypeOneAccount object,
    //which doesn't have methodTwo()
    productOne.getAccount().methodTwo()
    
    //fails because productTwo.getAccount() returns a TypeTwoAccount object,
    //which doesn't have methodOne()
    productTwo.getAccount().methodOne()