Skip to content

Instantly share code, notes, and snippets.

@LukasRychtecky
Last active September 28, 2022 13:16
Show Gist options
  • Save LukasRychtecky/e597a6b45b51ae5c3fc86284d8c3c43b to your computer and use it in GitHub Desktop.
Save LukasRychtecky/e597a6b45b51ae5c3fc86284d8c3c43b to your computer and use it in GitHub Desktop.
OOP vs. FP approach
// ----------------------------------------------------- common --------------------------------------------------------------
package io.applifting.jbtesting.module.usergist;
public class Email {
private final String email;
private Email(String email) {
this.email = email;
}
public static Email of(String input) {
throw new RuntimeException("Implement me");
}
}
public class UserId {
public UserId(Long id) {
this.id = id;
}
private final Long id;
public Long getId() {
return id;
}
}
// unifed user without any behaviour
public class User {
private final UserId id;
private final Email email;
private final OffsetDateTime invitedAt;
private final Optional<OffsetDateTime> confirmedAt;
private final UserStatus status;
public User(UserId id, Email email, OffsetDateTime invitedAt, Optional<OffsetDateTime> confirmedAt, UserStatus status) {
this.id = id;
this.email = email;
this.invitedAt = invitedAt;
this.confirmedAt = confirmedAt;
this.status = status;
}
}
public class UserInvitation {
public final String email;
public UserInvitation(String email) {
this.email = email;
}
}
public class UserNotFoundError extends Exception {}
// ------------------------------------------------ ala OOP approach --------------------------------------------------------
public class ConfirmedUser {
private final UserId id;
private final Email email;
private final OffsetDateTime invitedAt;
private final OffsetDateTime confirmedAt;
public ConfirmedUser(UserId id, Email email, OffsetDateTime invitedAt, OffsetDateTime confirmedAt) {
this.id = id;
this.email = email;
this.invitedAt = invitedAt;
this.confirmedAt = confirmedAt;
}
}
public class InvitedUser {
private final UserId id;
private final Email email;
private final OffsetDateTime invitedAt;
public InvitedUser(UserId id, Email email, OffsetDateTime invitedAt) {
this.id = id;
this.email = email;
this.invitedAt = invitedAt;
}
public static InvitedUser of(Supplier<OffsetDateTime> now, UserInvitation invitation) {
throw new RuntimeException("Implement me");
}
public ConfirmedUser confirm(Supplier<OffsetDateTime> now) {
return new ConfirmedUser(id, email, invitedAt, now.get());
}
}
public interface UserRepository {
Optional<InvitedUser> getInvitedUserById(UserId id);
Optional<ConfirmedUser> getConfirmedUserById(UserId id);
InvitedUser saveUser(InvitedUser user);
ConfirmedUser saveUser(ConfirmedUser user);
Optional<User> getById(UserId id);
}
public class UserService {
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
public InvitedUser inviteUser(UserInvitation invitation) {
InvitedUser user = InvitedUser.of(OffsetDateTime::now, invitation);
return repository.saveUser(user);
}
public ConfirmedUser confirmUser(UserId id) throws UserNotFoundError {
Optional<InvitedUser> maybeUser = repository.getInvitedUserById(id);
InvitedUser user = maybeUser.orElseThrow(UserNotFoundError::new);
ConfirmedUser confirmedUser = user.confirm(OffsetDateTime::now);
return repository.saveUser(confirmedUser);
}
}
// ------------------------------------------------ ala FP approach ---------------------------------------------------------
public class ConfirmedUser {
private final UserId id;
private final Email email;
private final OffsetDateTime invitedAt;
private final OffsetDateTime confirmedAt;
public ConfirmedUser(UserId id, Email email, OffsetDateTime invitedAt, OffsetDateTime confirmedAt) {
this.id = id;
this.email = email;
this.invitedAt = invitedAt;
this.confirmedAt = confirmedAt;
}
}
public class InvitedUser {
public final UserId id;
public final Email email;
public final OffsetDateTime invitedAt;
public InvitedUser(UserId id, Email email, OffsetDateTime invitedAt) {
this.id = id;
this.email = email;
this.invitedAt = invitedAt;
}
}
public class UserConfirmer {
private final Supplier<OffsetDateTime> now;
public UserConfirmer(Supplier<OffsetDateTime> now) {
this.now = now;
}
public ConfirmedUser confirm(InvitedUser user) {
return new ConfirmedUser(user.id, user.email, user.invitedAt, now.get());
}
}
public class UserInviter {
private final Supplier<OffsetDateTime> now;
public UserInviter(Supplier<OffsetDateTime> now) {
this.now = now;
}
public InvitedUser invite(UserInvitation invitation) {
throw new RuntimeException("Implement me");
}
}
public interface UserRepository {
Optional<InvitedUser> getInvitedUserById(UserId id);
Collection<InvitedUser> getInvitedUsersByIds(Collection<UserId> ids);
Optional<ConfirmedUser> getConfirmedUserById(UserId id);
InvitedUser saveUser(InvitedUser user);
ConfirmedUser saveUser(ConfirmedUser user);
Collection<ConfirmedUser> saveUsers(Collection<ConfirmedUser> users);
Optional<User> getById(UserId id);
}
public class UserService {
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
public InvitedUser inviteUser(UserInvitation invitation) {
InvitedUser user = new UserInviter(OffsetDateTime::now).invite(invitation);
return repository.saveUser(user);
}
// with optional
public ConfirmedUser confirmUser(UserId id) throws UserNotFoundError {
Optional<InvitedUser> maybeUser = repository.getInvitedUserById(id);
InvitedUser user = maybeUser.orElseThrow(UserNotFoundError::new);
ConfirmedUser confirmedUser = new UserConfirmer(OffsetDateTime::now).confirm(user);
return repository.saveUser(confirmedUser);
}
// without optional
public Collection<ConfirmedUser> confirmUsers(Collection<UserId> ids) {
return repository.getInvitedUsersByIds(ids)
.stream()
.map(new UserConfirmer(OffsetDateTime::now)::confirm)
.collect(Collectors.toList());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment