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 be taught 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, for those who’re utterly new to Android improvement, learn via our Starting Android Improvement tutorials to familiarize your self with the fundamentals.
Getting began
To start with, obtain the Kodeco Shell challenge utilizing the Obtain Supplies button on the prime or backside of this tutorial.
Open the starter challenge 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 allows you to enter instructions and present their output and errors. Moreover, there are two actions, one to cease a operating command and one to clear the output.
Construct and run the challenge. You must see the primary, and solely, display of the app:
Whoa, what’s occurring right here? As you possibly can see, the app at present refuses to run any instructions, it simply shows a non-cooperative message. Due to this fact, your job shall be to make use of OOP Finest 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 primarily based on knowledge. Every thing is modeled as objects that may carry out sure actions and talk with one another.
For instance, for those who have been to symbolize a automobile in object-oriented programming, one of many objects could be a Automotive. It might comprise actions equivalent to:
- Speed up
- Brake
- Steer left
- Steer proper
Courses and Objects
Probably the most essential distinctions in object-oriented programming is between lessons 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, equivalent to its prime pace, how briskly it may speed up, and so forth. It is sort of a blueprint for the automobile.
An object is an occasion of a automobile, for those who 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 lessons in KodecoShell app:
-
MainActivity
class represents the display proven while 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 employ:
non-public val commandProcessor: TerminalCommandProcessor = TerminalCommandProcessor()
Afterward, you possibly can use it by calling its capabilities, for instance:
commandProcessor.init()
Key Ideas of OOP
Now that you realize 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 grasp and keep.
Understanding Encapsulation and Kotlin Courses
Knowledge inside a category could be restricted. Be certain that different lessons can solely change the info in anticipated methods and stop state inconsistencies.
In brief, the surface world doesn’t have to know how a category does one thing, however what it does.
In Kotlin, you employ visibility modifiers to regulate the visibility of properties and capabilities inside lessons. Two of a very powerful ones are:
-
non-public
: property or operate is barely seen inside the category the place it’s outlined. -
public
: default visibility modifier if none is specified, property or operate is seen in all places.
Marking the inner knowledge of a category as non-public
prevents different lessons 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:
non-public 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 lessons to make use of course of()
to course of instructions by way of TerminalCommandProcessor
.
Notice you handed blocks of code for outputCallback
and errorCallback
parameters. Shell
will execute considered one of them when its course of
operate is named.
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.
Nevertheless, Android Studio will present the next error:Can not entry 'shell': it's non-public 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.
Because of this, now you need to see the output of the ps
command, which is the checklist of the at present operating processes.
Abstraction
That is much like encapsulation, it permits entry to lessons via a particular contract. In Kotlin, you possibly can outline that contract utilizing interfaces.
Interfaces in Kotlin can comprise declarations of capabilities and properties. However, the primary distinction between interfaces and lessons 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 eradicate 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.
Exchange init
operate with the next:
enjoyable init()
That is now an summary operate with no implementation. All lessons that implement TerminalCommandProcessor
interface should present the implementation of this operate.
Exchange 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
non-public 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 fromTerminalCommandProcessor
interface. - You create a personal property holding a
Shell
object for executing instructions. You cross the code blocks that cross the command output and errors tooutputCallback
wrapped inTerminalItem
objects. - Implementations of
init
,course of
andstopCurrentCommand
capabilities name applicableShell
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:
non-public val commandProcessor: TerminalCommandProcessor = ShellCommandProcessor()
Construct and run the app.