In Java, instantiate an interface object is as easy as new Interface()... and override all the required functions as below, on AnimationListener
private void doingSomething(Context context) {
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.fade_in);
animation.setAnimationListener(new Animation.AnimationListener() {
// All the other override functions
});
}
However, in Kotlin when we type
private fun doingSomething(context: Context) {
val animation = AnimationUtils.loadAnimation(context, android.R.anim.fade_in)
animation.setAnimationListener(Animation.AnimationListener(){
// All the other override functions
})
}
It error complaints unresolved References AnimationListener.
As explained in the documentation:
animation.setAnimationListener(object : Animation.AnimationListener {
// All the other override functions
})
Apparently the latest way (using Kotlin 1.0.5) of doing it is now without the parenthesis, given there's no empty constructor for the interface.
animation.setAnimationListener(object : Animation.AnimationListener {
// All the other override functions
})
Related
i'd like to override the method "dispose" by adding a function in it (let's imagine print()), but i'd like to keep its original purpose because otherwise it sometimes throws parent stability errors. How can I do it ?
You can use the super to run inherited parent class method:
class A {
a() {
print("a");
}
}
class B extends A {
#override
a() {
super.a();
print("b");
}
}
now running B().a():
B().a();
// output:
a
b
I am trying Libgdx Game Class to make a game.And I am following a book.There is an example. Example has 4 classes and 1 DesktopLauncher. DesktopLauncher use StarfishCollector3() class to main function. Despite I dont call create method and render method which are in GameBeta abstract class to StarfishCollector3, the project is working.Can you explain what I dont know.
class StarfishCollector3 : GameBeta() {
var turtle:Turtle=null
var starfish:ActorBeta=null
var ocean:ActorBeta=null
var winMessage:ActorBeta=null
var win:Boolean = true
override fun initialize() {
ocean= ActorBeta()
ocean.setTexture(Texture( Gdx.files.internal("water.jpg") ))
mainStage.addActor(ocean)
starfish = ActorBeta();
starfish.setTexture(Texture(Gdx.files.internal("starfish.png")) );
starfish.setPosition( 380F,380F );
mainStage.addActor( starfish );
turtle = Turtle()
turtle.setTexture( Texture(Gdx.files.internal("turtle-1.png")) )
turtle.setPosition( 20F,20F )
mainStage.addActor( turtle )
winMessage = ActorBeta();
winMessage.setTexture( Texture(Gdx.files.internal("you-win.png")) );
winMessage.setPosition( 180F,180F );
winMessage.setVisible( false );
mainStage.addActor( winMessage );
win = false }
override fun update(dt: Float) {
if (turtle.overlaps(starfish as ActorBeta)){
starfish.remove()
winMessage.setVisible(true)} }
}
abstract class GameBeta: Game() {
protected var mainStage: Stage=null
abstract fun initialize()
override fun create() {`
mainStage = Stage()
initialize() }
abstract fun update(dt:Float)
.
override fun render() {
var dt= Gdx.graphics.getDeltaTime()
mainStage.act()
update(dt)
Gdx.gl.glClearColor(0F,0F,0F,1F)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
mainStage.draw()
}
}
The heirarchy of StarfishCollector3 is that it extends GameBeta, which extends Game, which implements ApplicationListener.
In DesktopLauncher you instantiate a StarfishCollector3 and pass it as an implicit ApplicationListener to an Application constructor by calling something like new LwjglApplication(starfishCollectior, config);. When you instantiate that LwjglApplication (or Lwjgl3Application or AndroidApplication, etc. depending on backend), the constructor of that Application class sets up the game engine. It creates all the classes for managing OpenGL and drawing the game in a repeating loop, pausing and resuming, etc.
So the Application class is using your StarfishCollector3 as an ApplicationListener and calling its relevant lifecycle methods at the appropriate times.
Maybe it's really dumb question. But I cannot believe there is no resources, where it's described. Even from the official documentation. What I'm trying to do, it's create Anonymous class for the next function.
How to create Anonymous class in Dart with custom function something like next in Kotlin?
Handler(Looper.getMainLooper()).post(Runnable() {
#override
open fun run() {
//...
}
private fun local() {
//....
}
})
Dart does not support creating an anonymous class.
What you're trying to do is not possible.
On the other hand, you can create anonymous functions. So you could use that to mimic an anonymous class.
The idea is to add a constructor of your abstract class, that defer its implementation to callbacks.
abstract class Event {
void run();
}
class _AnonymousEvent implements Event {
_AnonymousEvent({void run()}): _run = run;
final void Function() _run;
#override
void run() => _run();
}
Event createAnonymousEvent() {
return _AnonymousEvent(
run: () => print('run'),
);
}
It's not strictly the same as an anonymous class and is closer to the decorator pattern. But it should cover most use-cases.
This is an alternative way, but not fully equivalent:
Problem, e.g.:
I would like to implement OnChildClickListener inline in my code without class. For this method:
void setOnChildClickListener(OnChildClickListener listener) {
...
}
Instead of this:
abstract class OnChildClickListener {
bool onChildClick(int groupPosition, int childPosition);
}
use this:
typedef OnChildClickListener = Function(int groupPosition, int childPosition);
And in code you can implement it in this way:
listView.setOnChildClickListener((int groupPosition, int childPosition) {
// your code here
});
In other words do not use abstract class, but use typedef.
There are three classes.
// in external library, which I don't want to modify
class ComponentBase {
// I want calling this to be disallowed
forceUpdate() {}
}
class ComponentBase_MyVersion extends ComponentBase {
// I want subclasses to always call this, instead of forceUpdate()
Update() {}
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// I want this to be disallowed
this.forceUpdate();
// forcing the subclass to call this instead
this.Update();
}
}
How can I accomplish this, with changes only to ComponentBase_MyVersion?
Is there a way to "hide" a base-class member?
Or perhaps a way to override the definition -- like with the "new" keyword in C# -- letting me mangle the method definition to at least make warnings appear when attempting to call it?
The OOP does not allow you to do this kind of method cancellation. You can impleement this funcion on your class with an Exception like you suggested, or use a composition: https://en.wikipedia.org/wiki/Composition_over_inheritance
Example 1:
class ComponentBase {
forceUpdate() {}
}
class ComponentBase_MyVersion extends ComponentBase {
Update() {}
forceUpdate() {
throw new Error("Do not call this. Call Update() instead.");
}
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// wil raise an exception
this.forceUpdate();
this.Update();
}
}
Example 2 (composition):
class ComponentBase {
forceUpdate() {}
}
class ComponentBase_MyVersion {
private _component: ComponentBase = ...;
Update() {}
// expose _component desired members ...
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// compilation error
this.forceUpdate();
this.Update();
}
}
I hope I helped.
Encapsulate implementation by replacing inheritance with composition Delegation Pattern
You can do this by adding the private access modifier on the forceUpdate method. This will result in all the subclasses being unable to access forceUpdate. However TypeScript does not support package access modifiers, but you can do this by replacing inheritance with composition.
class ComponentBase {
forceUpdate() {
}
}
class ComponentBase_MyVersion {
// Replace inheritance with composition.
private component: ComponentBase;
Update() {
this.component.forceUpdate();
}
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// Now subclass can't access forceUpdate method
this.Update();
}
}
Use a symbol in order to prevent external access to the method.
If you don't want to replace inheritance with composition, you can use Symbol to define a method. If your target is es5 you must configure tsconfig.json compilerOptions.lib to include es2015.symbol. Because every symbol is unique, any external module will not be able to obtain the symbol and access the method.
// libs.ts
let forceUpdate = Symbol("forceUpdate");
export class ComponentBase {
[forceUpdate]() {
}
}
export default class ComponentBase_MyVersion extends ComponentBase {
Update() {
this[forceUpdate]();
}
}
// test.ts
import ComponentBase_MyVersion from "./libs";
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// Now subclass can't access the forceUpdate method.
this.Update();
}
}
I found a way that seems to work -- that is, which causes warnings to appear when someone attempts to call forceUpdate() on a subclass instance.
forceUpdate(_: ()=>"Do not call this. Call Update() instead.") {
throw new Error("Do not call this. Call Update() instead.");
}
Now when I write new MyComponent().forceUpdate(), I get a compiler error, with the warning message containing a description telling me to use Update() instead.
EDIT: Apparently this only works because the base class already had this definition:
forceUpdate(callBack?: () => any): void;
If instead the base method is defined with no arguments originally (as in the OP), the above solution doesn't work.
However, if you have a case like mine (where there's an optional property like that, which you can narrow the return-type of), it works fine. (not sure if this return-type-narrowing is a bug, or intended)
I'm trying to find a way to test a abstract class constant that must exist and match/not match a value. Example:
// to be extended by ExternalSDKClild
abstract class ExternalSDK {
const VERSION = '3.1.1.';
}
class foo extends AController {
public function init() {
if ( ExternalSDK::VERSION !== '3.1.1' ) {
throw new Exception('Wrong ExternalSDK version!');
}
$this->setExternalSDKChild(new ExternalSDKChild());
}
}
Limitations... The framework we use doesn't allow dependency injection in the init() method. (Suggestion to refactor the init() method could be the way to go...)
The unit tests and code coverage I have run, cover all but the Exception. I can't figure out a way to make the ExternalSDK::Version to be different from what it is.
All thoughts welcome
First, refactor the call to new into a separate method.
Second, add a method to acquire the version instead of accessing the constant directly. Class constants in PHP are compiled into the file when parsed and cannot be changed.* Since they are accessed statically, there's no way to override it without swapping in a different class declaration with the same name. The only way to do that using standard PHP is to run the test in a separate process which is very expensive.
class ExternalSDK {
const VERSION = '3.1.1';
public function getVersion() {
return static::VERSION;
}
}
class foo extends AController {
public function init() {
$sdk = $this->createSDK();
if ( $sdk->getVersion() !== '3.1.1' ) {
throw new Exception('Wrong ExternalSDK version!');
}
$this->setExternalSDKChild($sdk);
}
public function createSDK() {
return new ExternalSDKChild();
}
}
And now for the unit test.
class NewerSDK extends ExternalSDK {
const VERSION = '3.1.2';
}
/**
* #expectedException Exception
*/
function testInitFailsWhenVersionIsDifferent() {
$sdk = new NewerSDK();
$foo = $this->getMock('foo', array('createSDK'));
$foo->expects($this->once())
->method('createSDK')
->will($this->returnValue($sdk));
$foo->init();
}
*Runkit provides runkit_constant_redefine() which may work here. You'll need to catch the exception manually instead of using #expectedException so you can reset the constant back to the correct value. Or you can do it in tearDown().
function testInitFailsWhenVersionIsDifferent() {
try {
runkit_constant_redefine('ExternalSDK::VERSION', '3.1.0');
$foo = new foo();
$foo->init();
$failed = true;
}
catch (Exception $e) {
$failed = false;
}
runkit_constant_redefine('ExternalSDK::VERSION', '3.1.1');
if ($failed) {
self::fail('Failed to detect incorrect SDK version.');
}
}