-1

I want to model a simple merchant website, with a Visitor, an Account, a Customer and an Administrator.

A Visitor can have a Basket.

A Visitor can become a Customer if it creates or provides Credentials.

A Customer and an Administrator are an Account with Credentials.

class Account {
    Credentials credentials;
    void logout();
    // other account management methods
}

class Admin extends Account {
}

class Visitor {
    Basket basket;
    // basket management methods
}

class Customer extends Visitor, Account {
    // needs a basket and credentials
}

I tried an Account interface, but account management methods have to be implemented both in Customer and Admin, and I don't want to duplicate that code. I saw that default implementation of interface methods exist in Java 8. But is there another way to achieve that without this hack?

Pierre
  • 1,322
  • 11
  • 17
  • 5
    Java has no multiple inheritance. – Diego Victor de Jesus Feb 11 '19 at 00:02
  • 2
    Customer is not an account. Customer might have an account though. – Ivan Feb 11 '19 at 00:17
  • 2
    You may want to consider composition (maybe w/decoration) instead. Return fields from the visitor and account instances as necessary or just directly. IMHO, inheritance/customization isn't really appropriate for aggregation. I've done it that way many times and it usually just gets messy. – Josh Feb 11 '19 at 00:23
  • 1
    In general, you should [prefer composition over inheritance](https://stackoverflow.com/questions/49002). Inheritance is just a mechanism for code reuse, and arguably it's not a very good mechanism. There are other ways to reuse code, usually by creating more objects to represent the reusable parts of things. (Separately from *implementation inheritance* there is also *API inheritance*, which in Java is implemented using interfaces. You can and usually should implement multiple interfaces whenever your object fulfills the contract of those interfaces.) – Daniel Pryden Feb 11 '19 at 00:37
  • In simpler words to Josh's answer, maintaining a method which returns the permission level to an `Account` (or what it can access e.g. `canDeleteAccount` or `getPermissions`), and having the subclasses modify that in order to allow you to define higher-level behavior around it. Furthermore this may even lead to the elimination of the concrete `Administrator`/`Customer` classes and leave you with an abstraction around any form of user – Rogue Feb 11 '19 at 00:40

3 Answers3

3

You have to reconsider the design and favor composition over inheritance. A simple rule - how to identify if you should use one or another: does the inheritance answer the question "is-a" or "has-a"?

Is Customer and Account? No. Customer is a User who MAY HAVE and Account.

Is customer a Visitor? Yes, he may be.

So you should extend your Customer from Visitor AND add an Account as a member of the class.

class Account {
    Credentials credentials;
    void logout();
    // other account management methods
}

class Admin {
     private Account account; // + Getters and setters
}

class Visitor {
    Basket basket;
    // basket management methods
}

class Customer extends Visitor {
    private Account account; // + Getters and setters
}

You can add an interface to make it even better in terms of SOLID:

interface Authenticable {
    Account getAccount();
    Account setAccount(Account account);
}

and make your Customer and Admin to implement it

class Customer extends Visitor implements Authenticable {
    private Account account; 
    @Override
    Account getAccount(){return account};
    @Override
    Account setAccount(Account account){this.account = account};
}

If you still want to avoid duplicating Account getters and setters - just extend Admin from the Customer and override getBasket() - thow NotImplementedException()

Azee
  • 1,809
  • 17
  • 23
  • 1
    A proper `Authenticable` interface wouldn't provide direct access to the account, but rather actions on an account and the `Account` itself stays encapsulated in the implementation. – Tom Feb 11 '19 at 01:29
  • Tom might be right. In that case actions with Account should be implemented in Utility method to avoid duplication. – Azee Feb 11 '19 at 04:20
  • Not only duplication, but also protecting the information stored in the `Account` instance, like the credentials. Giving that to other classes can result in a security leak. – Tom Feb 11 '19 at 10:18
  • Credentials shouldn't be stored opened even in databases. They should be encrypted. But you are right, that might be an issue anyway. – Azee Feb 11 '19 at 11:35
0

you may need an abstract method to infrastructure the class

0

Java has no multiple inheritance like python. This is fact.

You can change Account from class into interface. And create a class with name 'AccountImpl' that implement Account interface. In every class that you want to define account management methods like Admin or Customer you must have a field of Account interface and initilize that with AccountImpl class. something like this:

interface Account { // account management methods } 

class AccountImpl implements Account {
//implement account interface methods
}

class Admin {
    Account account;
    public Admin() {
       account = new AccountImpl();
}

class Customers extends Visitor {
    Account account;
    public Customers() {
       account = new AccountImpl();
}

For example if you want to logout you must say `customer.getAccount().logOut();

This is good practice because you don't duplicate the implementation of Account and also maybe in the future you want make deference between some credential. In this way you just have to create new AccountImpl class.

SamiAzar
  • 1,260
  • 13
  • 29