오늘의 TIL.. 정말 많은 내용을 다루고 싶어서 고민을 많이 했는데요! 아마 오늘은 11시까지 또 시간을 쓰면서 공부를 해야할 것 같네요 🥲
우선 제가 다루고 싶은 내용은 자바의 근간이라고 할 수 있는 Object-Oriented Project와 Polymorphism 입니다. 이러한 내용을 다루는 이유는 자바를 공부하고 계신 분들은 전부 알고 계실 것이라고 생각합니다! 그러나, 저는 Spring core 강의를 듣는데 프로그램의 전체적인 구조가 머리에 한번에 들어오질 않더라구요... 그래서 상기 시킬 겸 한번 다시 시작해보겠습니다.
OOP is just a set of objects. And this program performs the relations between each others and use each object as sort of a data in the class as the method.
- Absolutely, we get to spend much time to build this structure in the program. Notably, this structure has a bit lower speed than other paradigm.
Programming paradigm is an one of the way to build program for developers to grow their insight in terms of being a programmer.
This example, I got inspired from the Baekjoon, is about the sort in the criteria of length of each morpheme and the orders of the dictionary.
import java.util.Arrays;
// Word class to hold the word and its length
class Word implements Comparable<Word> {
String word;
int length;
public Word(String word) {
this.word = word;
this.length = word.length();
}
// Custom compareTo method to sort by length and then by lexicographical order
@Override
public int compareTo(Word other) {
if (this.length != other.length) {
return this.length - other.length;
}
return this.word.compareToIgnoreCase(other.word);
}
}
// WordSorter class to handle the sorting of words in a sentence
public class WordSorter {
private Word[] words;
public WordSorter(String sentence) {
String[] splitWords = sentence.split("\\s+"); // Split the sentence into words
words = new Word[splitWords.length];
for (int i = 0; i < splitWords.length; i++) {
words[i] = new Word(splitWords[i]);
}
}
public void sortWords() {
Arrays.sort(words);
}
public void printSortedWords() {
for (Word word : words) {
System.out.println(word.word);
}
}
public static void main(String[] args) {
// Example sentence
String sentence = "Hello world this is a Java program";
WordSorter sorter = new WordSorter(sentence);
sorter.sortWords();
sorter.printSortedWords();
}
}
class Word implements Comparable<Word> {
// instance to save basic informations we needed
String word;
int length;
// Constructor
public Word(String word) {
this.word = word;
this.length = word.length();
}
// compareTo Overriding to use in our class
// Sorting elements with the length of each words
@Override
public int compareTo(Word other) {
if (this.length != other.length) {
return this.length - other.length;
}
return this.word.compareToIgnoreCase(other.word);
}
}
This class encapsulates the concept of a "word" storing both the word itself and its length. In addition, We have to know compareTo method for sorting. it provides a way to compare this object with another Word obj. The comparison is based first on word length. If the lengths are equal, it sorts the words lexicographically order by compareToIgnoreCase.
public class WordSorter {
// set intial array to store result
private Word[] words;
public WordSorter(String sentence) {
String[] splitWords = sentence.split("\\s+"); // Split the sentence into words
// Initialize the size of the array
words = new Word[splitWords.length];
// Inject elements in it
for (int i = 0; i < splitWords.length; i++) {
words[i] = new Word(splitWords[i]);
}
}
public void sortWords() {
Arrays.sort(words);
}
public void printSortedWords() {
for (Word word : words) {
System.out.println(word.word);
}
}
public static void main(String[] args) {
String sentence = "Hello world this is a Java program";
WordSorter sorter = new WordSorter(sentence);
sorter.sortWords();
sorter.printSortedWords();
}
}
I also did it, I didn't know why this code tries to sort in another class, WordSorter. This is a reason why we should study Java everytime.
Word Class' Role :Comparable<Word> interface.compareTo method to specify the sorting criteria- words are first compared by length, and if the lengths are the same, they are sorted lexicographically.Comparable to set specific criteria up for our intention.WordSorter Class' Role :Word instances.Array.sort() on the array of Word objects. This method leverages the compareTo implementation to sort the array according to the defined natural ordering of the Word objects.Arrays.sort() relies on the comparison rules defined in compareTo() to decide the order of elements.abstract class Animal {
abstract void eat(); // Abstract method with no body
public void breathe() {
System.out.println("This animal breathes air.");
}
}
class Dog extends Animal {
@Override
void eat() {
System.out.println("The dog eats meat.");
}
}
Encapsulation is the bundling of data(attr) and methods that act on the data into a single unit or class. It also involves restricting access to some of the object's components, which is why it is often associated with data hiding.
public class Account {
private double balance; // Private variable, hidden from other classes
public Account(double balance) {
this.balance = balance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public double getBalance() {
return balance;
}
}
Inheritance
Inheritance is a mechanism where a new class is derived from an existing class. The new class is called a derived class, or subclass, and the existing class is called a base class, or superclass. It provides a method for creating a new class using details of an existing class without modifying it.
class Vehicle {
public void move() {
System.out.println("This vehicle moves.");
}
}
class Car extends Vehicle {
public void move() {
super.move(); // Calls the move method from Vehicle class
System.out.println("The car drives on the road.");
}
}
Polymorphism means "many forms", and it allows methods to do different things based on the object it is acting upon. In programming, it lets us define one interface and have multiple implementations.
class Bird {
public void sing() {
System.out.println("This bird sings.");
}
}
class Sparrow extends Bird {
public void sing() {
System.out.println("The sparrow chirps.");
}
}
public class TestPolymorphism {
public static void main(String[] args) {
Bird myBird = new Sparrow();
myBird.sing(); // Outputs "The sparrow chirps."
}
}
I will make a bit wrap-up about this topic again.
We gotta look through the defintion of this everytime. What is the Polymorphism?
A class should have only one reason to change, meaning it should have only one job or responsibility.
This principle aims to separate behaviors so that if bugs arise a result of your change, it will occur in the class with that responsibility and not affect other unrelated features.
public class UserSettings {
private User user;
// Constructor
public UserSettings(User user) {
this.user = user;
}
// Method to modify email as getting parameter from user
void changeEmail(String newEmail) {
if (EmailValidator.isValid(newEmail)) {
user.setEmail(newEmail);
}
}
}
public class EmailValidator {
static boolean isValid(String email) {
return email.contains("@");
}
}
Problem : Over-engineering can occur if too much emphasis is placed on creating classes with only one responsibility. This can lead to an excessive number of classes, making the system harder to navigate and manage.
- Refactor Gradually
Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
public abstract class Shape {
public abstract double area();
}
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double area() {
return Math.PI * radius * radius;
}
}
public class Square extends Shape {
private double side;
public Square(double side) {
this.side = side;
}
public double area() {
return side * side;
}
}
Allow systems to be extended with new functionality without altering existing source code, which can cause existing system behavior to change.

Subtypes must be substitutable for their base types, without altering the correctness of the program.
public class Rectangle {
protected int width, height;
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public int area() {
return width * height;
}
}
public class Square extends Rectangle {
public void setWidth(int width) {
super.setWidth(width);
super.setHeight(width);
}
public void setHeight(int height) {
super.setWidth(height);
super.setHeight(height);
}
}
Ensure that a derived class does not affect the behavior and expectations of the base class, thereby maintaining functionality through inheritance.
Clients should not be forced to depend upon interfaces they do not use.
public interface Shape {
double area();
}
public interface SolidShape {
double volume();
}
public class Cube implements Shape, SolidShape {
private double side;
public double area() {
return 6 * side * side;
}
public double volume() {
return side * side * side;
}
}
Keep interfaces small and specific to client needs so that implementing classes do not have to implement methods they do not require.
High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.
public interface DBConnectionInterface {
void connect();
}
public class MySQLConnection implements DBConnectionInterface {
public void connect() {
System.out.println("Connection to MySQL");
}
}
public class PasswordReminder {
private DBConnectionInterface dbConnection;
public PasswordReminder(DBConnectionInterface dbConnection) {
this.dbConnection = dbConnection;
}
}
Reduce dependencies amongst the code modules, making the system easier to understand and reduce the risk of changes in the low-level modules that affect high-level modules.
위의 내용을 정리하면서,,, 정말 머리가 많이 아픈것 같은데요 계산기를 만들때 이 부분을 고려해서 하기 위해 옆에다 띄워두고 만들어야 겠네요! 화이팅!
References
1. OOP
2. 김영한님 Spring Core