Level of encapsulation in JAVA

时间:2016-07-11 20:48:03

标签: java arraylist

I am working with a project and don't want to give access to the innermost classes. This is the class structure I am using,

// data types are not important unless mentioned
class One
{ 
    protected propertyOne;
    protected String id; 
}

class Two
{
    protected ArrayList<One> arrayOne;
    protected String id;
}

class Three
{
    protected ArrayList<Two> arrayTwo;
    protected otherProperty;
}

Now, main class will instantiate Three and should use Two and One through member methods. If I return any of ArrayList through get function, all the data can be easily changed from anywhere. So instead of ArrayList<Two>, I am returning ArrayList<Two.id> and then another method is called with particular Two.id. This takes care of keeping ArrayLists hidden but generates lots of code and extra objects because of ArrayList<Two.id> and ArrayList<One.id>.

In C++, I would have made a const method with const return type to ensure no changes in ArrayList.

Is there any smart way in Java to keep ArrayLists hidden?

1 个答案:

答案 0 :(得分:0)

We have a similar issue with a hibernate based API. We wanted to make "accidential" change impossible, enforcing the use of services to keep the business logic in one place and enforcing some access control on the API level.

We did resolve this with proxies and a derived Readonly interface.

So if you have a property in Two, the getX method is declared in a ReadonlyTwo interface. Whenever you return a list of Two, you declare the list to be of ReadonlyTwo. The programmer can hack around this by learning the API and he will see, when the object is really Two and can be typecasted. If you want to avoid that, you would have to wrap a proxy around the real Two object, implementing the ReadonlyTwo interface.

If you now return the lists as immutable lists, your API is pretty safe from external modification, even down to the object level.

// data types are not important unless mentioned
class One implements ReadonlyOne
{ 
    protected propertyOne;
    protected String id; 
}

class Two implements ReadonlyTwo
{
    protected ArrayList<? extends ReadonlyOne> arrayOne;
    protected String id;
}

class Three implements ReadonlyThree
{
    protected ArrayList<? extends ReadonlyTwo> arrayTwo;
    protected otherProperty;
}

Interfaces look like this (you did not add any getter/setter methods, so I make them up here):

interface ReadonlyThree {
    List<? extends ReadonlyTwo>getArrayTwo();   
}

Your application objects requires business methods to handle the modification of Two and One objects:

interface ThreeService {
    ReadonlyTwo addTwo(p1, p2, p3) throws BusinessException;
    void removeTwo(ReadonlyTwo twoRO) throws BusinessException;
    List<? extends ReadonlyTwo>findTwoByPredicate(Predicate p) throws BusinessException;
}