I have a rather theoretical question.
For example I have an class of objects - like Table. And this table could be colored with different colors - red, blue and yellow. If the table was not colored before, the result is clear. Otherwise the following rules are in play:
red + yellow --> orange
blue + yellow --> green
red + blue --> purple
red + blue + yellow --> brown
What is the nicest and the most elegant way to implement this? Is there any design patter for such a case? My variant may be too straightforward:
public class Table{
private boolean isRed;
private boolean isBlue;
private boolean isYellow;
public String colorRed(){
isRed = true;
if (isBlue && isYellow)
return "brown";
if (isBlue)
return "purple";
if (isYellow)
return "orange";
return "red";
}
//... the same for other colors
}
I Suggest a state machine:
Suggested implementation:
interface IColorState {
IColorState AddBlue();
IColorState AddRed();
IColorState AddYellow();
}
class BlueState: IColorState {
public override AddBlue() {return new BlueState()}
public override AddRed() {return new PurpleState()}
public override AddYellow() {return new GreenState()}
}
class YellowState: IColorState {...}
class RedState: IColorState {...}
class PurpleState: IColorState {
public override AddBlue() {return new PurpleState()}
public override AddRed() {return new PurpleState()}
public override AddYellow() {return new BrownState()}
}
Related
Is there a way to declare virtual methods and virtual properties inside an abstract class in Kotlin like in c #?
C# Example:
public abstract class myAbstractClass {
private string _myString = "";
protected virtual string MyString
{
get { return _myString ; }
set { _myString = value; }
}
public virtual string getMyString(){
return _myString
}
}
I'm not familiar with C#, but if I understand the virtual and protected keywords correctly then it seems you want an overridable property that can be read from outside the class but can only be set from within the class or by a subclass. If that's the case then I believe the equivalent Kotlin code would be:
abstract class MyAbstractClass {
open var myString = ""
protected set
}
But if you really need the two properties and the function then the equivalent would be:
abstract class MyAbstractClass {
private var _myString = ""
protected open var myString by ::_myString
open fun getMyStringAlt() = _myString
}
Unfortunately, at least on the JVM, the getMyStringAlt() function cannot be named getMyString() because it clashes with the getter for the myString property. I'm not sure if there's a workaround.
The equivalent code would be:
abstract class MyAbstractClass {
protected open var myString = "foo"
open fun customGetString() = myString
}
This gives you a myString property that can be overriden by subclasses, and a customGetString function can can be overridden by subclasses. But if they don't override it, they get the default behaviour. Some examples:
class ConcreteClassA : MyAbstractClass()
class ConcreteClassB : MyAbstractClass() {
override var myString = "bar"
}
class ConcreteClassC : MyAbstractClass() {
override fun customGetString() = myString + "extra"
}
class ConcreteClassD : MyAbstractClass() {
override var myString = "baz"
override fun customGetString() = myString + "extra"
}
fun main() {
println(ConcreteClassA().customGetString())
println(ConcreteClassB().customGetString())
println(ConcreteClassC().customGetString())
println(ConcreteClassD().customGetString())
}
Output
foo
bar
fooextra
bazextra
I want to access animals class color from dogs reference
as I am new to kotlin if something is wrong guide me
fun main() {
var dogs = Dogs("pug")
println("Color of Dog :${dogs.color}")//Black
println("Color of Animal:${}")//White
}
private open class Animals {
open var color: String = "White"
}
private class Dogs(var breed: String) : Animals() {
override var color: String = "Black"
}
You can only do this by exposing another property (or function) in Dogs that accesses the super class property to get the value being held in that field, and using that:
private class Dogs(var breed: String) : Animals() {
override var color: String = "Black"
var animalColor: String
get() = super.color
set(value) {
super.color = value
}
}
But this is an abuse of inheritance, and runs counter to common expectations of OOP. A single property should not have a different meaning in a subclass, such that external classes have to distinguish between them. If Dogs has some characteristic that is different than the property in Animals, then it should have a new, different property for that rather than overriding.
Also, you don't need to override just to change the initial value of a var. Overriding creates a second, redundant backing field. Your Dogs class should be like this if you want Dogs to have a different default value for color:
private class Dogs(var breed: String) : Animals() {
init {
color = "Black"
}
}
the code below compiles while it is impossible to go through conditions Color.Dark and Color.Light as these two classes are abstract.
Did I miss something ?
sealed class Color () {
sealed class Dark () {
class DarkRed : Color()
class DarkBlue : Color()
}
sealed class Light {
class LightRed : Color()
class LightBlue : Color()
}
}
fun eval(c: Color) =
when (c) {
is Color.Dark -> println("Dark")
is Color.Dark.DarkRed -> println("Dark Red")
is Color.Dark.DarkBlue -> println("Dark Blue")
is Color.Light -> println("Light")
is Color.Light.LightRed -> println("Light Red")
is Color.Light.LightBlue -> println("Light Blue")
}
fun main(args: Array<String>) {
val dr = Color.Dark.DarkRed()
eval(dr)
}
Two left indented conditions are never satisfied because Color.Dark and Color.Lightdo not inherit Color, and not because they are abstract. It means that 2 out of 6 is branches are useless, you can safely delete them. But other 4 branches (is Color.Dark.DarkRed, etc.) go through all Color subclasses, and Color is a sealed class, so when can be used without else branch.
This question already has answers here:
What are sealed classes in Kotlin?
(3 answers)
Closed 3 years ago.
I'm newbie of Kotlin. I'm learning sealed classes and I don't understand how could I use it in Android development. Can you give me an example?
It's useful when you want to define a closed list of subclasses.
You can use possibility for data classes to extend sealed classes . Example:
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
// the `else` clause is not required because we've covered all the cases
}
Declaration:
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
Kotlin documentation says:
Sealed classes are used for representing restricted class hierarchies, when a value can have one of the types from a limited set, but cannot have any other type.
Let's take a simple example. You have a sealed abstract class that represents a boolean expression:
sealed class BooleanExpression {
abstract fun evalate(): Boolean
}
Now let's define a class that extends this sealed class:
class OrBooleanExpression(val elem1: Boolean, val elem2: Boolean) : BooleanExpression() {
override fun evalate() = elem1 or elem2
}
Let's now assume for the example that we want a method that prints only the members of a boolean expression. For our or boolean expression, we would have the following:
Elem1 true / Elem2 false
We could implement our method like the following:
fun printMembers(expr: BooleanExpression) = when (expr) {
is OrBooleanExpression -> print("Elem1 ${expr.elem1} / Elem2 ${expr.elem2}")
}
Up to that point, our compiler is happy. Nothing is wrong. In fact, in our when, we have taken into account all subclasses of the sealed class.
Let's add now another boolean expression:
class NotBooleanExpression(val elem1: Boolean) : BooleanExpression() {
override fun evalate(): Boolean = !elem1
}
Now the compiler returns an error:
'when' expression must be exhaustive, add necessary 'is NotBooleanExpression' branch or 'else' branch instead
Now we have two possilities to solve this problem. The first is to add a clause for the new operation:
fun printMembers(expr: BooleanExpression) = when (expr) {
is OrBooleanExpression -> print("Elem1 ${expr.elem1} / Elem2 ${expr.elem2}")
is NotBooleanExpression -> print("Elem1 ${expr.elem1}")
}
Or we could add a else clause:
fun printMembers(expr: BooleanExpression) = when (expr) {
is OrBooleanExpression -> print("Elem1 ${expr.elem1} / Elem2 ${expr.elem2}")
else -> print("Unknown elements")
}
In both case, the compilation works because we have handled all subclasses of the sealed class.
If now we take into account a langage that doesn't have currently sealed class, like Java. We won't be able to do that at compile time. You will therefore need to implement the following using the design pattern Visitor.
interface BooleanExpression {
abstract Boolean evaluate();
abstract <T> T accept(Visitor<T> visitor);
}
class NotBooleanExpression implements BooleanExpression {
private String elem1;
public NotBooleanExpression(String elem1) {
this.elem1 = elem1;
}
public Boolean getElem1() {
return elem1;
}
#Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
}
class OrBooleanExpression implements BooleanExpression {
private String elem1;
private String elem2;
public NotBooleanExpression(String elem1, String elem2) {
this.elem1 = elem1;
this.elem2 = elem2;
}
public Boolean getElem1() {
return elem1;
}
public Boolean getElem2() {
return elem2;
}
#Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
}
class Visitor<T> {
T visit(NotBooleanExpression expr);
T visit(OrBooleanExpression expr);
}
class Test {
public void printMembers(expr: BooleanExpression) {
expr.accept(new Visitor<Void>() {
#Override
public Void visit(NotBooleanExpression expr) {
System.out.println("Elem1 " + expr.getElem1());
return null;
}
#Override
public Void visit(OrBooleanExpression expr) {
System.out.println("Elem1 " + expr.getElem1() + " / Elem2" + expr.getElem2());
return null;
}
};
}
}
How to use method references to refer to super class methods?
In Java 8 you can do SubClass.super::method.
What would be the syntax in Kotlin?
Looking forward to your response!
Conclusion
Thanks to Bernard Rocha!
The syntax is SubClass::method.
But be careful. In my case the subclass was a generic class. Don't forget to declare it as those:
MySubMap<K, V>::method.
EDIT
It still doesn't work in Kotlin.
Hers's an example in Java 8 of a method reference to a super class method:
public abstract class SuperClass {
void method() {
System.out.println("superclass method()");
}
}
public class SubClass extends SuperClass {
#Override
void method() {
Runnable superMethodL = () -> super.method();
Runnable superMethodMR = SubClass.super::method;
}
}
I'm still not able to do the same in Kotlin...
EDIT
This is an example how I tried to achieve it in Kotlin:
open class Bar {
open fun getString(): String = "Hello"
}
class Foo : Bar() {
fun testFunction(action: () -> String): String = action()
override fun getString(): String {
//this will throw an StackOverflow error, since it will continuously call 'Foo.getString()'
return testFunction(this::getString)
}
}
I want to have something like that:
...
override fun getString(): String {
//this should call 'Bar.getString' only once. No StackOverflow error should happen.
return testFunction(super::getString)
}
...
Conclusion
It's not possible to do so in Kotlin yet.
I submitted a feature report. It can be found here: KT-21103 Method Reference to Super Class Method
As the documentation says you use it like in java:
If we need to use a member of a class, or an extension function, it
needs to be qualified. e.g. String::toCharArray gives us an extension
function for type String: String.() -> CharArray.
EDIT
I think you can achieve what you want doing something like this:
open class SuperClass {
companion object {
fun getMyString(): String {
return "Hello"
}
}
}
class SubClass : SuperClass() {
fun getMyAwesomeString(): String {
val reference = SuperClass.Companion
return testFunction(reference::getMyString)
}
private fun testFunction(s: KFunction0<String>): String {
return s.invoke()
}
}
Don't know if it is possible to get the reference to super class's function, but here is an alternative to what you want to achieve:
override fun getString(): String = testFunction { super.getString() }
According to Bernardo's answer, you might have something like this. It doesn't have remarkable changes.
fun methodInActivity() {
runOnUiThread(this::config)
}
fun config(){
}
What is more, in the incoming 1.2 version you can use just
::config