Object-Oriented Programming (OOP) is the most well-liked pc programming paradigm. Utilizing it correctly could make your life, and your coworkers’, lives simpler. On this tutorial, you’ll construct a terminal app to execute shell instructions on Android.
Within the course of, you’ll study the next:
Key ideas of Object-Oriented Programming.
SOLID ideas and the way they make your code higher.
Some Kotlin particular good-to-knows.
Additionally, should you’re fully new to Android growth, learn via our Starting Android Growth tutorials to familiarize your self with the fundamentals.
Getting began
To start with, obtain the Kodeco Shell undertaking utilizing the Obtain Supplies button on the prime or backside of this tutorial.
Open the starter undertaking in Android Studio 2022.2.1 or later by choosing Open on the Android Studio welcome display:
The app consists of a single display much like Terminal on Home windows/Linux/MacOS. It helps you to enter instructions and present their output and errors. Moreover, there are two actions, one to cease a working command and one to clear the output.
Construct and run the undertaking. You must see the principle, and solely, display of the app:
Whoa, what’s happening right here? As you may see, the app at the moment refuses to run any instructions, it simply shows a non-cooperative message. Due to this fact, your job will probably be to make use of OOP Greatest Practices and repair that! You’ll add the power to enter instructions and show their output.
Understanding Object-Oriented Programming?
Earlier than including any code, you need to perceive what OOP is.
Object-Oriented Programming is a programming mannequin based mostly on information. Every part is modeled as objects that may carry out sure actions and talk with one another.
For instance, should you had been to signify a automobile in object-oriented programming, one of many objects could be a Automobile. It will include actions resembling:
Speed up
Brake
Steer left
Steer proper
Courses and Objects
One of the crucial necessary distinctions in object-oriented programming is between courses and objects.
Persevering with the automobile analogy, a category could be a concrete automobile mannequin and make you should buy, for instance — Fiat Panda.
A category describes how the automobile behaves, resembling its prime velocity, how briskly it may possibly speed up, and many others. It is sort of a blueprint for the automobile.
An object is an occasion of a automobile, should you go to a dealership and get your self a Fiat Panda, the Panda you’re now driving in is an object.
Let’s check out courses in KodecoShell app:
MainActivity class represents the display proven whenever you open the app.
TerminalCommandProcessor class processes instructions that you just’ll enter on the display and takes care of capturing their output and errors.
Shell class executes the instructions utilizing Android runtime.
TerminalItem class represents a bit of textual content proven on the display, a command that was entered, its output or error.
MainActivity makes use of TerminalCommandProcessor to course of the instructions the consumer enters. To take action, it first must create an object from it, known as “creating an object” or “instantiating an object of a category”.
To attain this in Kotlin, you utilize:
personal val commandProcessor: TerminalCommandProcessor = TerminalCommandProcessor()
Afterward, you may use it by calling its capabilities, for instance:
commandProcessor.init()
Key Rules of OOP
Now that you recognize the fundamentals, it’s time to maneuver on to the important thing ideas of OOP:
Encapsulation
Abstraction
Inheritance
Polymorphism
These ideas make it attainable to construct code that’s straightforward to know and keep.
Understanding Encapsulation and Kotlin Courses
Knowledge inside a category will be restricted. Ensure different courses can solely change the info in anticipated methods and forestall state inconsistencies.
In brief, the skin world doesn’t must understand how a category does one thing, however what it does.
In Kotlin, you utilize visibility modifiers to regulate the visibility of properties and capabilities inside courses. Two of crucial ones are:
personal: property or operate is just seen inside the category the place it’s outlined.
public: default visibility modifier if none is specified, property or operate is seen in every single place.
Marking the interior information of a category as personal prevents different courses from modifying it unexpectedly and inflicting errors.
To see this in motion, open TerminalCommandProcessor class and add the next import:
import com.kodeco.android.kodecoshell.processor.shell.Shell
Then, add the next inside the category:
personal val shell = Shell(
outputCallback = { outputCallback(TerminalItem(it)) },
errorCallback = { outputCallback(TerminalItem(it)) }
)
You instantiated a Shell to run shell instructions. You possibly can’t entry it exterior of TerminalCommandProcessor. You need different courses to make use of course of() to course of instructions through TerminalCommandProcessor.
Notice you handed blocks of code for outputCallback and errorCallback parameters. Shell will execute certainly one of them when its course of operate known as.
To check this, open MainActivity and add the next line on the finish of the onCreate operate:
commandProcessor.shell.course of(“ps”)
This code tries to make use of the shell property you’ve simply added to TerminalCommandProcessor to run the ps command.
Nonetheless, Android Studio will present the next error:Can’t entry ‘shell’: it’s personal in ‘TerminalCommandProcessor’
Delete the road and return to TerminalCommandProcessor. Now change the init() operate to the next:
enjoyable init() {
shell.course of(“ps”)
}
This code executes when the appliance begins as a result of MainActivity calls TerminalViews‘s LaunchEffect.
Construct and run the app.
In consequence, now you need to see the output of the ps command, which is the listing of the at the moment working processes.
Abstraction
That is much like encapsulation, it permits entry to courses via a selected contract. In Kotlin, you may outline that contract utilizing interfaces.
Interfaces in Kotlin can include declarations of capabilities and properties. However, the principle distinction between interfaces and courses is that interfaces can’t retailer state.
In Kotlin, capabilities in interfaces can have implementations or be summary. Properties can solely be summary; in any other case, interfaces may retailer state.
Open TerminalCommandProcessor and substitute class key phrase with interface.
Notice Android Studio’s error for the shell property: Property initializers aren’t allowed in interfaces.
As talked about, interfaces can’t retailer state, and you can not initialize properties.
Delete the shell property to remove the error.
You’ll get the identical error for the outputCallback property. On this case, take away solely the initializer:
var outputCallback: (TerminalItem) -> Unit
Now you might have an interface with three capabilities with implementations.
Change init operate with the next:
enjoyable init()
That is now an summary operate with no implementation. All courses that implement TerminalCommandProcessor interface should present the implementation of this operate.
Change course of and stopCurrentCommand capabilities with the next:
enjoyable course of(command: String)
enjoyable stopCurrentCommand()
Courses in Kotlin can implement a number of interfaces. Every interface a category implements should present implementations of all its summary capabilities and properties.
Create a brand new class ShellCommandProcessor implementing TerminalCommandProcessor in processor/shell package deal with the next content material:
package deal com.kodeco.android.kodecoshell.processor.shell
import com.kodeco.android.kodecoshell.processor.TerminalCommandProcessor
import com.kodeco.android.kodecoshell.processor.mannequin.TerminalItem
class ShellCommandProcessor: TerminalCommandProcessor { // 1
// 2
override var outputCallback: (TerminalItem) -> Unit = {}
// 3
personal val shell = Shell(
outputCallback = { outputCallback(TerminalItem(it)) },
errorCallback = { outputCallback(TerminalItem(it)) }
)
// 4
override enjoyable init() {
outputCallback(TerminalItem(“Welcome to Kodeco shell – enter your command …”))
}
override enjoyable course of(command: String) {
shell.course of(command)
}
override enjoyable stopCurrentCommand() {
shell.stopCurrentCommand()
}
}
Let’s go over this step-by-step.
You implement TerminalCommandProcessor interface.
You declare a property named outputCallback and use the override key phrase to declare that it’s an implementation of property with the identical identify from TerminalCommandProcessor interface.
You create a personal property holding a Shell object for executing instructions. You go the code blocks that go the command output and errors to outputCallback wrapped in TerminalItem objects.
Implementations of init, course of and stopCurrentCommand capabilities name applicable Shell object capabilities.
You want yet one more MainActivity change to check the brand new code. So, add the next import:
import com.kodeco.android.kodecoshell.processor.shell.ShellCommandProcessor
Then, substitute commandProcessor property with:
personal val commandProcessor: TerminalCommandProcessor = ShellCommandProcessor()
Construct and run the app.