For an assignment I am designing a simple "chatroom" system. It is very rudimentary and simply involves objects of a Person class sending messages to each other through a separate Chatroom object.
Below is my Person class (did not include getter/setter methods for sake of brevity).
public class Person {
protected String firstName;
protected String lastName;
protected String message;
Person(String fn, String ln)
{
firstName = fn;
lastName = ln;
}
public void sendMessage(String msg, Person rec)
{
rec.receiveMessage(msg);
}
public String receiveMessage(String msg)
{
message = msg;
}
}
these Person objects are instantiated and send messages to each other through the Chatroom class using the sendMessage method.
Now I am supposed to design a larger Person class, into multiple classes by adding Address, Name and Contact classes to the multi class system. The problem is I don't know how to associate these classes with the Person class. At first I tried to make an inheritance relationship with the Name class adding the middleInitial field, but i dont see the utility in this.
public class Name extends Person {
protected String middleInitial;
Name(String fn, String ln) {
super(fn, ln);
}
public static void main(String args[])
{
}
public String getMI()
{
return middleInitial;
}
public void setMI(String mi)
{
middleInitial = mi;
}
I don't understand the need for these separate classes, couldn't all this information be stored in the Person object? Can someone help me understand a way to design these classes separately but all be part of the Person object?
In this case - yes name should be part of Person. In OOP (Object Oriented Programming) "extends" means "is-a". In your case "Name" is definitely not "is-a" Person. Person should contain name - so "Name" should be a property and not "extend" person.
Related
I have set of objects of different types.
Ex : Employee emp, adress adr
These two classes have list of properties
public class Employee{
private Stringname;
private int age;
}
public class Adress {
private String HouseNo;
private string Street;
private string pin;
}
Each attribute is assigned with some 2 character value
Name (NA), age (AG), HouseNo(HN),Street(ST), pin(PN)
I need to construct a string with these data and delimit with a %
Output:
NA%Vidhya%AG%30%HN%80%ST%1st cross%PN%100100
Each class knows it own data best so I would let each class be responsible for generating the string. As I understand it the two char codes for each field are unique for each class and member and only used when generating the string so only the class would need them.
interface AttributeDescription {
String generateDescription();
}
public class Employee implements AttributeDescription {
//members...
public String generateDescription() {
return String.format(“NA%%%s%%AG%%%d”, name, age)
}
Then simply call this method for all objects implementing the interface.
AttributeDescription object = ...
String attr = object.generateDescription();
I don't think it can be generalized more than this given the requirements.
Update
It might be better to have a builder class for building the string to get a more unified behavior between classes. Here is an example
public class AttributeBuilder {
private builder = new StringBuilder();
public String getAttribute() {
return builder.toString();
}
public void add(String code, String value) {
if (value == null) {
return;
}
builder.append(code);
builder.append(‘%’);
builder.append(value);
builder.append(‘%’);
}
}
And then you would also have to implement add(...) methods for other data types in a similar fashion. The builder could then be used like
public String generateDescription() {
AttributeBuilder builder = new AttributeBuilder();
builder.add(“NA”, name);
builder.add(“AG”, age);
return builder.getAttribute();
}
I'm wondering if there is some design pattern to help me with this problem.
Let's say I have a class Person which has three attributes: name, nickname and speaksEnglish and an Enum PersonType with TypeOne, TypeTwo and TypeThree.
Let's say if a Person has nickname and speaksEnglish it's a TypeOne. If it has nickame but doesn't speaksEnglish, it's a TypeTwo. If it does not have nickame, so it's TypeThree.
My first thought would have a method with some if-else and returning the related Enum. In the future I can have more attributes in Person and other types of PersonType to decide.
So, my first thought was create a method with a bunch of if (...) { return <PersonType> } or switch-case, but I was wondering if there is some design pattern I can use instead of ifs and switch-case.
I will recomend you to use just simple inheritance with immutable objects.
So, at first you have to create abstract class:
public abstract class AbstractPerson {
private final String name;
private final Optional<String> nickname;
private final boolean speaksEnglish;
private final PersonType personType;
protected AbstractPerson(final String name, final Optional<String> nickname, final boolean speaksEnglish, final PersonType personType) {
this.name = name;
this.nickname = nickname;
this.speaksEnglish = speaksEnglish;
this.personType = personType;
}
public String getName() {
return name;
}
public Optional<String> getNickname() {
return nickname;
}
public boolean getSpeaksEnglish() {
return speaksEnglish;
}
public PersonType getPersonType() {
return personType;
}
}
With PersonType enum:
public enum PersonType {
TypeOne, TypeTwo, TypeThree;
}
Now, we have three options with corresponding constructors in child classes:
public final class EnglishSpeakingPerson extends AbstractPerson {
public EnglishSpeakingPerson(final String name, final String nickname) {
super(name, Optional.of(nickname), true, PersonType.TypeOne);
}
}
public final class Person extends AbstractPerson {
public Person(final String name, final String nickname) {
super(name, Optional.of(nickname), false, PersonType.TypeTwo);
}
public Person(final String name) {
super(name, Optional.empty(), false, PersonType.TypeThree);
}
}
In this case, our concrete classes are immutable and its type is defined in moment of creation. You don't need to create if-else ladders - if you want to create new type, just create new class/constructor.
I don't think Type can really be an attribute of a Person. I am not against #ByeBye's answer but with that implementation you will still end up changing Person class when there are new types introduced.
X type of person is ultimately a person itself. Say a Manager or Developer are both employees of a company, so it makes a lot of sense to have them as specialized classes that derive from an Employee. Similarly in your case, having person type as an attribute and then doing all if-else stuff clearly violates SOLID.
I would instead have specific implementations of Person class and mark itself as an abstract one.
public abstract class Person {
public Person(string name) {
Name = name;
}
public abstract string Name { get; set; }
public abstract string NickName { get; set; }
public abstract bool SpeaksEnglish { get; set; }
}
public class TypeOnePerson : Person {
public TypeOnePerson(string name, string nickName) : base(name) {
NickName = nickName; // Validate empty/ null
}
SpeaksEnglish = true;
}
public class TypeTwoPerson : Person {
public TypeOnePerson(string name, string nickName) : base(name) {
NickName = nickName; // Validate empty/ null
}
SpeaksEnglish = false;
}
I also think that this question is language-agnostic, it is a pure design question. So please bear with me as the code above is in C#. That doesn't matter, however.
As far as OO principles are considered why to create object with combinations of optional attributes? If its question of one or two then Optional approach will remain maintainable, but type will be based on many combinations (in future code will be full of Boolean Algebra) and question also says "...In the future I can have more attributes in Person and other types of PersonType to decide.".
I would suggest approach of using Decorator pattern, which allows us to create customized objects with complete code reuse. Person will be Component and Optional attributes (they are types e.g NickName with validation as behavior) will be concrete decorators.
Any addition to Person and adding new Concrete Decorator type remain two separate concerns. Decorator Pattern is a best candidate for this kind of requirement. Its Intent from GOF book (by Erich gamma) pattern Catalog says - "Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality". [though for very small number of expected extensions earlier answers make more sense.]
I cannot access a field of a class that is a concrete type inheriting from an abstract class.
In Java I create a class of External student that extends Student
*/
public class ExternalStudent extends Student {
String currentSchool;
public ExternalStudent(String name, Integer age, String studentIdentifier, String currentSchool) {
super(name, age, studentIdentifier);
this.currentSchool = currentSchool;
}
}
where student is
public abstract class Student {
//Attributes
String studentIdentifier;
Integer age;
String name;
//Associations
List<Subject> subject = new ArrayList<Subject>();
PersonalDetails personaldetails;
//Methods
public void setSubject () {
this.subject.add(new Subject("Name"));
}
//Constructors
public Student(String name, Integer age, String studentIdentifier){
this.age = age;
this.name = name;
this.studentIdentifier = studentIdentifier;
}
}
and external student is set up by my class Application
public class ApplicationC {
//Attributes
private String personalStatement;
private String applicationForm;
//Associations
Registration registration;
Student student;
ApplicationTest applicationtest;
//Methods
public void setApplicationResult(String result){
this.applicationtest = new ApplicationTest(result);
}
//Constructor
public ApplicationC (String personalStatement, String name){
this.registration = new Registration();
this.student = new ExternalStudent("Tom",16,"78954","DHS");
}
}
I've set up a simple test class
public void testPostCondition() throws ParseException{
ApplicationC instance = new ApplicationC("test statement","test name");
instance.setApplicationResult("pass");
assertEquals("pass",instance.applicationtest.result);
instance.student.age = 16;
instance.student.studentIdentifier = "78954";
instance.student.name = "Tom";
instance.student.currentSchool = "test"; //Error as field does not exist
}
But I cannot access the current school of the student instance (who must be an externalStudent). How can I access this field in order to test my code?
In ApplicationC, the student field is declared with the Student class :
Student student;
Methods available on an objects relies on the declared type, not the object really instantiated.
And currentSchool is only declared in the subclass ExternalStudent.
So, you cannot access it in this way.
A workaround is downcasting Student to ExternalStudent :
((ExternalStudent)instance.student).studentIdentifier = "78954";
And generally, it is better to check the type of the instance before doing it :
if (instance.student instanceof ExternalStudent){
((ExternalStudent)instance.student).studentIdentifier = "78954";
}
As a general advice, in Java, you should favor the private modifier for fields and if you need to manipulate the base class and access to some fields specific to the subclass, you could define a method in the base class that returns null or Optional and override it in the subclass with the return of the field.
It avoids cast that may be error prone and that often are symptoms of a conception problem.
Your instance is an AplicationC,
So, "instance.student" is a "Student".
"Student" does not have the "currentSchool" property.
to get to it
* add "currentSchool" property to "Student"
or
* cast your "instance.student" to "ExternalStudent"
note: you will need to handle all the exceptions and over-head of casting etc'
Hope this helps
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.
I have 3 classes, Person, Student, and Teacher. Student and Teacher extend Person. How can I access instance variables from within Person? Like if Student and Teacher both have an internal list of names, how can I access both name arrays from within the parent class?
class Person
{
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void printAllNames() { //<-- How do you do this?
for(Student s : students) //can't access students array
System.out.println(s.getName());
for(Teacher t : teachers)
System.out.println(t.getName());
}
}
class Student extends Person
{
protected Student[] students;
Student(String name)
{
this.name = name;
students[students.length] = this;
}
}
class Teacher extends Person
{
protected Teacher[] teachers;
Teacher(String name)
{
this.name = name;
teacher[teachers.length] = this;
}
}
You class design is incorrect. Your Student class should not contain a field students as other students are not part of a Student instance (i.e. composition should not be used here). Instead you should create lists of students outside of these classes if they are required. Same for teachers of course.
A student could have a list of friends, but such relations are better stored outside the class itself as well. The list of friends does is not part of a student. What does need to be part of student depends on what you are trying to model (an address could be part of student if that helps to define student for administration purposes).
If you want to access fields of a higher level class you could downcast to Student from Person but again, that would normally be considered as a technical solution for a design problem.
Ignoring the issues with the design and the use of arrays as others have mentioned, if you want to print the names depending on whether it's a student and teacher, you should make printAllNames abstract and have the descendant classes provide their own print implementation. The base class should not know about specifics of properties or methods in subclasses.
class Person
{
...
public abstract void printAllNames();
}
class Student extends Person
{
...
public void printAllNames() {
for (Student s : students)
System.out.println(s.getName());
}
}
class Teacher extends Person
{
...
public void printAllNames() {
for (Teacher t : teachers)
System.out.println(t.getName());
}
}
Your code is having issue in array.length() because there is no any method like length(). you can access that by array.length.
second there is no name variable in your Student class and you made name as private field in Person Class change that to public or protected.
third you can pass argument in your method like
public void printAllNames(Student[] students, Teacher[] teachers)
and check once.