JetBrains Academy: Interfaces - Kamil-Jankowski/Learning-JAVA GitHub Wiki

JetBrains Academy: Interfaces

Mutable geometric shapes:

Suppose, you are writing a geometric engine. Now it includes classes and interfaces Circle, Rectangle, Movable and Scalable.

You need:

  1. to write a new interface MutableShape that extends both existing interfaces;
  2. to implement the new interface by each class;
  3. to override methods move and scale in both classes:
    • scale should multiply the radius of a circle by the specified factor;
    • scale should multiply width and height of a rectangle by the specified factor;
    • move should add dx and dy to the center of a circle;
    • move should add dx and dy to the upper-left corner of a rectangle.

See the provided code and read comments to understand your task better. Now the code is not compiled.

Note:

  • do not remove existing classes and their members (including getters and constructors).
  • do not make your classes and interfaces public.

After your changes, the following code should be compiled:

MutableShape circle = new Circle(2.0f, 3.5f, 10.1f);
 
circle.move(10.1f, 20.2f);
circle.scale(2.2f);
 
((Circle) circle).getRadius();
interface Movable {

    void move(float dx, float dy);
}

interface Scalable {

    void scale(float factor);
}

interface MutableShape extends Movable, Scalable {
}

final class Circle implements MutableShape {

    // Defines the horizontal position of the center of the circle
    private float centerX;

    // Defines the vertical position of the center of the circle
    private float centerY;

    // Defines the radius of the circle
    private float radius;

    public Circle(float centerX, float centerY, float radius) {
        this.centerX = centerX;
        this.centerY = centerY;
        this.radius = radius;
    }

    public float getCenterX() {
        return centerX;
    }

    public float getCenterY() {
        return centerY;
    }

    public float getRadius() {
        return radius;
    }
    @Override
    public void move(float dx, float dy){
        centerX += dx;
        centerY += dy;
    }
    @Override
    public void scale(float factor){
        radius *= factor;
    }
}

final class Rectangle implements MutableShape {

    // Defines the X coordinate of the upper-left corner of the rectangle.
    private float x;

    // Defines the Y coordinate of the upper-left corner of the rectangle.
    private float y;

    // Defines the width of the rectangle.
    private float width;

    // Defines the height of the rectangle.
    private float height;

    public Rectangle(float x, float y, float w, float h) {
        this.x = x;
        this.y = y;
        this.width = w;
        this.height = h;
    }

    public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }

    public float getWidth() {
        return width;
    }

    public float getHeight() {
        return height;
    }
    @Override
    public void move(float dx, float dy){
        x += dx;
        y += dy;
    }
    @Override
    public void scale(float factor){
        height *= factor;
        width *= factor;
    }
}

Account Service:

You are given an interface named AccountService. The interface has two abstract methods:

  • findAccountByOwnerId(long id) that returns Account found by owner id or null.
  • countAccountsWithBalanceGreaterThan(long balance) that returns the number of accounts with the balance greater than the passed value. There are also two other classes: Account (id, balance, owner) and User (id, firstName, lastName). See their implementations in the provided code template.

You need to implement the AccountService interface and its two methods. Your implementation should be named AccountServiceImpl. It should have a constructor with one argument — an array of accounts. The implementation must keep the array inside. The first method should search for an account by owner id in the array, the second one — count the number of accounts that meet the given condition in the array.

Here's an example of an instance:

Account[] accounts = ...
AccountService service = new AccountServiceImpl(accounts);
interface AccountService {
    /**
     * It finds an account by owner id
     * @param id owner unique identifier
     * @return account or null
     */
    Account findAccountByOwnerId(long id);
    /**
     * It count the number of account with balance > the given value
     * @param value
     * @return the number of accounts
     */
    long countAccountsWithBalanceGreaterThan(long value);
}

// Declare and implement your AccountServiceImpl here
class AccountServiceImpl implements AccountService{

    private Account[] arrayOfAccounts;

    public AccountServiceImpl(Account[] accounts){
        this.arrayOfAccounts = accounts;
    }

    @Override
    public Account findAccountByOwnerId(long id) {
        for (Account acc: arrayOfAccounts){
            if(acc.getOwner().getId() == id){
                return acc;
            }
        }
        return null;
    }

    @Override
    public long countAccountsWithBalanceGreaterThan(long value) {
        long counter = 0;
        for (Account acc : arrayOfAccounts){
            if(acc.getBalance() > value){
                counter++;
            }
        }
        return counter;
    }
}

class Account {

    private long id;
    private long balance;
    private User owner;

    public Account(long id, long balance, User owner) {
        this.id = id;
        this.balance = balance;
        this.owner = owner;
    }

    public long getId() { return id; }

    public long getBalance() { return balance; }

    public User getOwner() { return owner; }
}

class User {

    private long id;
    private String firstName;
    private String lastName;

    public User(long id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public long getId() { return id; }

    public String getFirstName() { return firstName; }

    public String getLastName() { return lastName; }
}

Compact strings with AsciiCharSequence:

Write a class named AsciiCharSequence that implements compact storage of ASCII-character sequences. Their codes can be stored in one single byte, unlike Unicode characters. Compared to the standard String class, your class will require twice less memory (before Java 9).

The class AsciiCharSequence should:

  • implement the interface java.lang.CharSequence;
  • have a constructor that takes a byte array;
  • define methods length, charAt, subSequence, and toString. You can see the declaration of methods and their behavior in the description of java.lang.CharSequence (JavaDoc or sources).
public class AsciiCharSequence implements CharSequence{

    private byte[] sequence;

    public AsciiCharSequence(byte[] args){
        this.sequence = args;
    }

    @Override
    public int length() {
        return sequence.length;
    }

    @Override
    public char charAt(int index) {
        return (char) sequence[index];
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        byte[] subSequence = new byte[end-start];
        for (int i = 0; i < subSequence.length; i++) {
            subSequence[i] = sequence[start+i];
        }
        return new AsciiCharSequence(subSequence);
    }

    @Override
    public String toString(){
        char[] charSequence = new char[sequence.length];
        for(int i = 0; i < sequence.length; i++){
            charSequence[i] = (char) sequence[i];
        }
        return String.valueOf(charSequence);
    }
}