How to use encapsulation? - java

After I read online E-book.They said the benefit of encapsulation is "A class can change the data type of a field and users of the class do not need to change any of their code.". I don't understand what they say in the point. What is the main meaning of the point? Can you give an example,please?

Let's take a simple class Vehicles, which maintains a list:
public class Vehicles {
private ArrayList<String> vehicleNames;
Vehicles() {
vehicleNames = new ArrayList<String>();
}
public void add(String vehicleName) {
vehicleNames.add(vehicleName);
}
}
This will be used by a client in the following way:
public class Client {
Public static void main(String []args) {
Vehicles vehicles = new Vehicles();
vehicles.add("Toyota");
vehicles.add("Mazda");
}
}
Now if Vehicles changes its internal private vehicleNames field to be a LinkedList instead, Client would be unaffected. That is what the book is talking about, that the user/client does not need to make any changes to account for the changes in the class due to encapsulation.

Encapsulation is really important in Object-Oriented Programming. Using encapsulation, you can hide information from users who use your class library/API.
"And why do I need to hide stuff from the users?", you ask. There are a lot of reason. One main reason is that some users who are naughty or just don't know what the API is doing may mess with your classes and stuff. Let me give you an example.
Suppose you have a class here:
public class Computer {
public int coreCount;
}
As you can see here, coreCount is declared public. That means all other classes can access it. Now imagine a naughty person do this:
Computer myPC = new Computer ();
myPC.coreCount = 0;
Even fools can tell that this doesn't make any sense. It might also affect your program's other stuff. Imagine you want to divide by the core count. An Exception would occur. So to prevent this, we should create setters and getters and mark the field private.
C# Version:
public class Computer {
private int coreCount;
public int CoreCount {
get {return coreCount;}
set {
if (value > 0)
coreCount = value;
}
}
}
Java version
public class Computer {
private int coreCount;
public int getCoreCount () {return coreCount;}
public void setCoreCount (int value) {
if (value > 0)
coreCount = value;
}
Now no one can set the core count to non-positive values!

Here's an example of encapsulation. Say we have a Person class, like so
class Person {
private String name;
private String email;
public String getName() { return this.name; }
public String getEmail() { return this.email; }
public void setName(String name) { this.name = name; }
public void setEmail(String email) { this.email = email; }
}
And at some point, we decide we need to store these values not as a couple strings, but as a HashMap (for some reason or another).
We can change our internal representation without modifying the public interface of our Person class like so
class Person {
HashMap<String, String> data;
public Person() {
this.data= new HashMap<String, String>();
}
public String getName() { return this.data.get("name"); }
public String getEmail() { return this.data.get("email"); }
public void setName(String name) { this.data.put("name", name); }
public void setEmail(String email) { this.data.put("email", email); }
}
And from the client code perspective, we can still get and set Strings name and email without worrying about anything else.

Related

Can we enforce inheritence after super class objects have been individually created? ObjA obj = new ObjB();

Is there a way to enforce inheritance between objects after they have been created Individually? Consider the example given below
class Test{
class publisher{
public String pubName;
//10-15 other members here
public String getPublisher(){
return pubName;
}
public void setName(String name){
pubName = name;
}
}
class author extends publisher{
public String authorName;
//5-10 other members here
public String getAuthor(){
return authorName;
}
#Override
public void setName(String name){
authorName = name;
}
}
public static void main(String Args[]){
publisher pub1 = new publisher();
pub1.setName("Amanda Book House");
//I want to do something like this below?
pub1 auth1 = new author();
//I want to create an author who has inherited information from pub1
//so auth1.getPublisher() should give me Amanda Book House
}
}
So to be specific I want to know if while creating a derived class object, there is a way to inherit information from a base class object that's already been created. I know that when a derived object is created, an implicit call is made to super class constructor. How does that come into the picture for this case?
No, you can't do that. What you can do instead is ensure that the base classes (Publisher in your case) have copy constructors, so that you can pass in a Publisher instance to the Author constructor to copy its state into the object being constructed:
class Publisher {
private String pubName;
public Publisher(Publisher other) { // ***
this.pubName = other.pubName; // ***
} // ***
//10-15 other members here
public String getPublisher(){
return pubName;
}
public void setName(String name){
pubName = name;
}
}
class Author extends Publisher{
private String authorName;
public Author(Publisher pub) { // ***
super(pub); // ***
} // ***
//5-10 other members here
public String getAuthor(){
return authorName;
}
#Override
public void setName(String name){
authorName = name;
}
}
So then:
Publisher pub1 = new publisher();
pub1.setName("Amanda Book House");
Author auth1 = new Author(pub1); // *** *Copies* the state from pub1
It's important to note that this makes a copy; if you change the state of pub1 later (for instance, change the name), it won't have any effect on auth1's state.
Side note: You can obviously do what you like in your own code, but when asking for help, please follow standard Java naming conventions, it's important for making your code readable to others.
Side note 2: If you have accessors for something (like pubName), the instance variable holding it should be private.
I've done both of those things in the above.

Encapsulating builders in Java

I have 2 builders in my codebase, which can be accessed like this :
return new Developer.Builder("John", "Doe").age(30).build();
return new Manager.Builder("Eve", "Page").age(40).build();
I want to make the API simpler by encapsulating in an enum :
return Google.Developer.Builder("John", "Doe").age(30).build();
return Google.Manager.Builder("Eve", "Page").age(40).build();
My goal is to simplify the process for
Changing company names from Google to Microsoft
If a new role is added (apart from Developer and Manager), users of my code can know about it in one place.
Only option which comes to my mind is having company name as enum - but then I won't be able to implement builder pattern.
You can create an API similar to what you describe:
enum Google {
Developer, Manager;
public Builder builder(String name) {
return new Builder(this, name);
}
public static class Builder {
public Builder(Google role, String name) { ... }
public Builder age(int age) { ... }
public Employee build() { ... }
}
}
Now you can write
Employee e = Google.Developer.builder("John").age(30).build();
I don't see what the point is for all this. Do the builders somehow depend on the company and role in a non-trivial way?
If not, you can define the Builder as a separate class and use an interface to mark what ever represents roles in companies, similar to Sleiman's answer.
You could even parametrize the Employee class with company, if this makes sense in your application...
interface CompanyRole { /* just a marker */ }
enum Google implements CompanyRole {
...
Employee.Builder<Google> builder(String name) {
return new Employee.Builder<>(this, name);
}
}
class Employee<T extends CompanyRole> {
...
static class Builder<T extends CompanyRole> {
EmployeeBuilder(T role, String name) { ... }
Employee<T> build() { ... }
}
}
And you can still write
Employee<Google> e = Google.Developer.builder("John").age(30).build();
You can add an interface that represents a company
interface Company{
}
And have an enum of well known companies,
enum Companies implements Company{
GOOGLE,
MICROSOFT,
...
}
And now in your builder you can add a method that takes a Company rather an enum
Builder company(Company company){
addCompany(company);
return this;
}
And construct it fluently like this
Developer.Builder("John", "Doe").company(Companies.GOOGLE).age(30).build();
And now companies can either be constants or something you load from a db (anything that implements Company). It is type-safe either ways.
Review
return Google.Developer.DevBuilder("John", "Doe").age(30).build();
This makes no sense. Taking a closer look, above call leads to a class Google, which contains an inner class Developer. That class defines a static method called DevBuilder that takes 2 parameters, first and last name, and returns an instance of Builder/DeveloperBuilder.
This is not an object oriented, extensible approach. Even though you gave us very little context, I'd argue that companies are static objects, which are not subject to change. Referring to the example you made in the comments - a new company is more likely than a new CompressFormat.
Further, there is no possibility to change behaviour via polymorphism, except for the dynamic calls to age(int) and build().
Dynamic approach
Below a concept of a more dynamic approach (of course mechanics should be added, to make sure that there is only one object for a company, e.g. Company.byName("Google") etc.)
public static void main(String[] args) {
Company google = new Google();
Manager manager = google.newManager();
}
static abstract class Company {
public Manager newManager() {
return new ManagerBuilder("Eve", "Page").age(40).build();
}
}
static class Google extends Company {
}
You can easily add new companies and change the way a manager (or any other employee) is created, you can also use the default.
Refactoring
With some more playing around, you can remove the boiler plate code in the classes for employees and their corresponding builders, by creating two base classes as follows
static abstract class Person<P extends Person<P>> {
protected final String firstName;
protected final String lastName;
protected final int age;
public <T extends AbstractBuilder<P, T>> Person(AbstractBuilder<P, T> builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
}
}
static abstract class AbstractBuilder<P extends Person, T extends AbstractBuilder<P, T>> {
protected final String firstName;
protected final String lastName;
protected int age;
public AbstractBuilder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
abstract T self();
abstract P build();
T age(int age) {
this.age = age;
return self();
}
}
Utilizing the above, creating a class Manager and its Builder yields following code
static class Manager extends Person<Manager> {
public <T extends AbstractBuilder<Manager, T>> Manager(AbstractBuilder<Manager, T> builder) {
super(builder);
}
}
static class ManagerBuilder extends AbstractBuilder<Manager, ManagerBuilder> {
public ManagerBuilder(String firstName, String lastName) {
super(firstName, lastName);
}
#Override
ManagerBuilder self() {
return this;
}
#Override
Manager build() {
return new Manager(this);
}
}
Managerand its Builder, or any other employee can be extended with more fields.

Why Java Method Reference of instance method cannot be assigned to Consumer interface

Here is my Code :
public class SearchByLambda {
private Map<String,Consumer<Person>> searchCritertiaHolder = new HashMap<String,Consumer<Person>>();
private static final String AGED = "aged";
public SearchByLambda(){
searchCritertiaHolder.put(AGED, (Person p)-> {p.filterAgedPerson(p);} );
}
private Consumer<Person> getFilter(String personType){
return searchCritertiaHolder.get(personType);
}
public static void main(String[] args) {
SearchByLambda searchUsage = new SearchByLambda();
Person p = new Person(59,"shailesh");
Person p1 = new Person(58,"ganesh");
searchUsage.getFilter(AGED).accept(p);
searchUsage.getFilter(AGED).accept(p1);
Person.printAgedPersons();
}
}
class Person{
private static List<Person> agedPersons = new ArrayList<>();
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(int age,String name){
this.age = age;
this.name = name;
}
public void filterAgedPerson(Person person){
if(person.getAge() > 58){
agedPersons.add(person);
}
}
public static void printAgedPersons(){
for(Person person : agedPersons){
System.out.println(person.getName());
}
}
}
When I replace following Lambda expression
searchCritertiaHolder.put(AGED, (Person p)-> {p.filterAgedPerson(p);});
with
searchCritertiaHolder.put(AGED, Person::filterAgedPerson);
it gives me compilation error. I am using java 8 and and compiling through eclipse. Why is this so? Why cannot I assign method reference for instance method of any arbitrary object to consumer functional interface?
Your definition of filterAgedPerson takes a Person as an argument, even though it is not a static method. It doesn't need to, and it shouldn't if you want to use it as a Consumer<Person>. What you are ending up with is something compatible with BiConsumer<Person, Person>.
It might help to think of it this way: method references to non-static methods always take an "extra" argument which is used as this.
The easiest way for you to fix this with your current code structure is to modify the filterAgedPerson method to not take a Person as an argument
public void filterAgedPerson() {
if (this.getAge() > 58) {
agedPersons.add(person);
}
}
As an aside, you might want to also consider making your filters Predicate<Person> instead of Consumer<Person> and moving the results handling elsewhere. This will give you more flexibility as things get more complicated.

How do I use Java getters and setters with a collection of data without explicitly typing out the attributes for each item?

I am very new to Java and to programming in general, and I have an assessment to complete where I load employees (with name, age, and department attributes; department can be only one of four enumerated values) into a program that will sort them by age and tell if the age is a prime number. The assignment requires Company, Department, and Employee classes. I am confident that I can figure out age/prime components — I know how to google for algorithms. What I am struggling with is putting all the discrete pieces into a cohesive whole.
Here is what I have so far. I've put in one employee, but the way I'm doing it seems completely inelegant and inefficient. I am sure there is a better way, but I've hit a mental block.
EDIT: as was pointed out below, I was unclear. What I am asking help with is populating the data structure.
Company class:
public class Company {
static Employee one = new Employee();
public static void main(String[] args) {
one.setName("Counting Guru");
one.setAge(55);
one.setDepartment(DepartmentList.ACCOUNTING);
}
}
DepartmentList class:
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;
public enum DepartmentList {
ACCOUNTING, MARKETING, HUMANRESOURCES, INFORMATIONSYSTEMS;
public static void main(String[] args) {
Map<DepartmentList,String>
enumMap=new EnumMap<DepartmentList,String>(DepartmentList.class);
enumMap.put(DepartmentList.ACCOUNTING, "Accounting");
enumMap.put(DepartmentList.MARKETING, "Marketing");
enumMap.put(DepartmentList.HUMANRESOURCES, "Human Resources");
enumMap.put(DepartmentList.INFORMATIONSYSTEMS, "Information Systems");
Set<DepartmentList> keySet = enumMap.keySet();
for (DepartmentList department : keySet) {
String value = enumMap.get(department);
System.out.println("ENUMMAP VALUE:"+value);
}
}
}
Employee class:
public class Employee {
String empName;
int empAge;
DepartmentList empDept;
Employee() {
}
public String getName() {
return empName;
}
public void setName(String name) {
this.empName = name;
}
public int getAge() {
return empAge;
}
public void setAge(int age) {
this.empAge = age;
}
public DepartmentList getDepartment() {
return empDept;
}
public void setDepartment(DepartmentList department) {
this.empDept = department;
}
public Employee(String empName, int empAge, DepartmentList empDept){
}
}
I also have a Department class, but it's currently empty.
Am I on the right track? Can someone give me a nudge? Thank you!
Don't hard-code the data inside the Java program. Put the data in a file and write methods to load the data.
If you MUST hardcode the data in the program, use something like this sample:
public class Employee
{
String name;
int age;
public Employee(String name, int age)
{
this.name = name;
this.age = age;
}
// getters, setters, etc.
}
In the main program
private static Employee[] empData =
{
new Employee("John Smith", 50),
new Employee("Fred Jones", 25),
.
.
.
};
Now you have a static array of Employee objects that you can "load" into your data structure.
If you're asking if there is something like a property in Java, no, there isn't (at least not yet).
If you're asking how to populate your objects something like an IOC container, like Spring, would be a better choice.
Now as it comes to your code you have two main methods in two different classes. Only one will be called. If you want to create a static instance you will be better do
static Employee one = new Employee("Counting Guru", 55, DepartmentList.ACCOUNTING);
or
static Employee one = new Employee();
static {
one.setName("Counting Guru");
one.setAge(55);
one.setDepartment(DepartmentList.ACCOUNTING);
}
When it comes to the enum then you'll better define a constructor for it
public enum DepartmentList {
ACCOUNTING("Accounting"), MARKETING("Marketing");
private String displayName;
public DepartmentList(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return diplayName;
}
}
In the Employee constructor you need to assign the field values to the ones received as arguments.

String Array object in Java

I am trying to print the first element on the two arrays in my Athlete class, country and name. I also need to create a object that simulates three dive attemps an athlete had (that is initially set to zero). I am new to OOP and I dont know how to go abouts doing this in my main... as far as constructors go. This is what i have done so far...
this is the main:
import java.util.Random;
import java.util.List;
public class Assignment1 {
public static void main(String[] args) {
Athlete art = new Athlete(name[0], country[0], performance[0]);
}
}
I just really am not sure what to do...
And this is the class with the arrays.
import java.util.Random;
import java.util.List;
public class Athlete {
public String[] name = {"Art", "Dan", "Jen"};
public String[] country = {"Canada", "Germant", "USA"};
//Here i would like to create something that would be representing 3 dive attemps (that relate to dive and score. eventually.)
Athlete(String[] name, String[] country, Performance[] performance) {
this.name = name;
this.country=country;
this.performance=performance;
}
public Performance Perform(Dive dive){
dive.getDiveName();
return null;
}
public String[] getName() {
return name;
}
public void setName(String[] name) {
this.name = name;
}
public String[] getCountry() {
return country;
}
public void setCountry(String[] country) {
this.country = country;
}
}
thanks in advance for any help and input!
btw there is other classes too, just not relevant atm..
First, as for your Athlete class, you can remove your Getter and Setter methods since you have declared your instance variables with an access modifier of public. You can access the variables via <ClassName>.<variableName>.
However, if you really want to use that Getter and Setter, change the public modifier to private instead.
Second, for the constructor, you're trying to do a simple technique called shadowing. Shadowing is when you have a method having a parameter with the same name as the declared variable. This is an example of shadowing:
----------Shadowing sample----------
You have the following class:
public String name;
public Person(String name){
this.name = name; // This is Shadowing
}
In your main method for example, you instantiate the Person class as follow:
Person person = new Person("theolc");
Variable name will be equal to "theolc".
----------End of shadowing----------
Let's go back to your question, if you just want to print the first element with your current code, you may remove the Getter and Setter. Remove your parameters on your constructor.
public class Athlete {
public String[] name = {"Art", "Dan", "Jen"};
public String[] country = {"Canada", "Germany", "USA"};
public Athlete() {
}
In your main method, you could do this.
public static void main(String[] args) {
Athlete art = new Athlete();
System.out.println(art.name[0]);
System.out.println(art.country[0]);
}
}
Currently you can't access the arrays named name and country, because they are member variables of your Athelete class.
Based on what it looks like you're trying to do, this will not work.
These arrays belong in your main class.
Your attempt at an athlete class seems to be dealing with a group of athletes, which is a design fault.
Define a class to represent a single athlete, with fields that represent the athlete's attributes:
public class Athlete {
private final String name;
private final String country;
private List<Performance> performances = new ArrayList<Performance>();
// other fields as required
public Athlete (String name, String country) {
this.name = name;
this.country = country;
}
// getters omitted
public List<Performance> getPerformances() {
return performances;
}
public Performance perform(Dive dive) {
// not sure what your intention is here, but something like this:
Performance p = new Performance(dive, this);
// add new performance to list
performances.add(p);
return p;
}
}
Then your main method would use ti like this:
public class Assignment1 {
public static void main(String[] args) {
String[] name = {"Art", "Dan", "Jen"};
String[] country = {"Canada", "Germant", "USA"};
Dive[] dive = new Dive[]{new Dive("somersault"), new Dive("foo"), new Dive("bar")};
for (int i = 0; i < name.length; i++) {
Athlete athlete = new Athlete(name[i], country[i]);
Performance performance = athlete.perform(dive[i]);
// do something with athlete and/or performance
}
}
}
I think you are a little messed up with what you doing.
Athlete is an object, athlete has a name, i has a city where he lives.
Athlete can dive.
public class Athlete {
private String name;
private String city;
public Athlete (String name, String city){
this.name = name;
this.city = city;
}
--create method dive, (i am not sure what exactly i has to do)
public void dive (){}
}
public class Main{
public static void main (String [] args){
String name = in.next(); //enter name from keyboad
String city = in.next(); //enter city form keybord
--create a new object athlete and pass paramenters name and city into the object
Athlete a = new Athlete (name, city);
}
}
public static void main(String[] args) {
public String[] name = {"Art", "Dan", "Jen"};
public String[] country = {"Canada", "Germant", "USA"};
// initialize your performance array here too.
//Your constructor takes arrays as an argument so you need to be sure to pass in the arrays and not just objects.
Athlete art = new Athlete(name, country, performance);
}
First off, the arrays are pointless, let's get rid of them: all they are doing is providing values for mock data. How you construct mock objects has been debated ad nauseum, but clearly, the code to create the fake Athletes should be inside of a unit test. I would use Joshua Bloch's static builder for the Athlete class, but you only have two attributes right now, so just pass those in a Constructor. Would look like this:
class Athlete {
private String name;
private String country;
private List<Dive> dives;
public Athlete(String name, String country){
this.name = name;
this.country = country;
}
public String getName(){
return this.name;
}
public String getCountry(){
return this.country;
}
public String getDives(){
return this.dives;
}
public void addDive(Dive dive){
this.dives.add(dive);
}
}
Then for the Dive class:
class Dive {
private Athlete athlete;
private Date date;
private double score;
public Dive(Athlete athlete, double score){
this.athlete = athlete;
this.score = score;
this.date = new Date();
}
public Athlete getAthlete(){
return this.athlete;
}
public Athlete getAthlete(){
return this.athlete;
}
public Athlete getAthlete(){
return this.athlete;
}
}
Then make a unit test and just construct the classes, and manipulate them, make sure that they are working. Right now they don't do anything so all you could do is assert that they are retaining the Dives that you are putting in them. Example:
#Test
public void testThatDivesRetainInformation(){
Athlete art = new Athlete("Art", "Canada");
Dive art1 = new Dive(art, 8.5);
Dive art2 = new Dive(art, 8.0);
Dive art3 = new Dive(art, 8.8);
Dive art4 = new Dive(art, 9.2);
assertThat(art.getDives().size(), is(5));
}
Then you could go through and add tests for things like, making sure that you can't construct a dive without an athlete, etc.
You could move construction of the athletes into the setup method of the test so you could use it all over the place. Most IDEs have support for doing that with a refactoring.

Categories