I'm writing simple Chat System. There are should be two implementations of communication:
using Serialization
and XML (own protocol).
Implementation is chosen by user in GUI.
So, is it okay to use if-else or switch for choosing implementation ?
I have thought about Java Reflection but I can't figure out how to realize it.
Any suggestions ?
I'd say it can be "okay" to use a if-else or switch statement to choose the implementation. A better (and more OOP) approach would be something along these lines:
//////////////////////////////////
// The communication interfaces
//////////////////////////////////
public interface IChatCommunicationFactory {
public String toString();
public IChatCommunication create();
}
public interface IChatCommunication {
public sendChatLine(String chatLine);
public registerChatLineReceiver(IChatLineReceiver chatLineReceiver);
}
public interface IChatLineReceiver {
public void onChatLineReceived(String chatLine);
}
//////////////////////////////////
// The communication interface implementations
//////////////////////////////////
public class XMLChatCommunicationFactory implements IChatCommunicationFactory {
public String toString() {
return "XML implementation";
}
public IChatCommunication create() {
return new XMLChatCommunication();
}
}
public class XMLChatCommunication implements IChatCommunication {
private XMLProtocolSocket socket;
public XMLChatCommunication() {
// set up socket
}
public sendChatLine(String chatLine) {
// send your chat line
}
public registerChatLineReceiver(IChatLineReceiver chatLineReceiver) {
// start thread in which received chat lines are handled and then passed to the onChatLineReceived of the IChatLineReceiver
}
}
// Do the same as above for the Serialization implementation.
//////////////////////////////////
// The user interface
//////////////////////////////////
public void fillListBoxWithCommuncationImplementations(ListBox listBox) {
listBox.addItem(new XMLChatCommunicationFactory());
listBox.addItem(new SerializationChatCommunicationFactory());
}
public IChatCommunication getChatCommunicationImplementationByUserSelection(ListBox listBox) {
if (listBox.selectedItem == null)
return null;
IChatCommunicationFactory factory = (IChatCommunicationFactory)listBox.selectedItem;
return factory.create();
}
You could go one step further and implement something like a ChatCommunicationFactoryRegistry where each IChatCommunicationFactory is registerd. That would help to move the "business" logic out of the user interface because the fillListBoxWithCommuncationImplementations() method would only need to know the registry, not the individual implementations anymore.
Inheritance and plain old Java is the 'pattern' to use here. Instantiate the implementation to be used, and save a reference to it in the object that needs to use it. When the user switches methods, instantiate the new one.
Related
My question is about what should be the most OOP solution and the right design pattern for my situation. We have a user entity and multiple account entities belong to the user. Account entities can have multiple states and we can execute multiple operations on accounts. The outcome of these operations is based on the account entity's state.
I have the following code which is based mostly on switch (sometimes it looks like a few "if"). I would like to change it but cannot find the right design pattern.
enum Status {
ACTIVE, INACTIVE, DELETED;
}
#Entity
class Account {
private long id;
private long userid;
private Status status;
//...
}
class AccountService{
Account delete(long id) {
//...
if (accountInfo.getSatus() == DELETED) {
throw new IllegalOperationException();
}
if (accountInfo.getStatus() == ACTIVE || accountInfo.getStatus()) {
accountInfo.setStatus(DELETED);
accountInfoRepository.save(accountInfo);
}
}
Account create (Account account) {
// various operations based on state
}
}
I really want to refactor these codes, I fear that as soon as our service grows it will contain more "magic" and will be hard to maintain. And if we would like to introduce a new state it will be nearly impossible.
My junior mind thought that I should have state objects which would implement all the operations, in pseudo-code style:
class AccountService {
private StateFactory stateFactory;
private AccountRepository accountRepository;
Account delete(long id) {
final Optional<Account> account = accountRepository.findById(id);
Account deletedAccount = account.map(stateFactory::getByState)
.map(accountState -> accountState.delete(account))
.orElseThrow(() -> new IllegalOperationException());
return accountRepository.save(deletedAccount);
}
Account create (Account account) {
// various operation based on state
}
}
and:
class ActiveState extends AccountState {
#Override
public Account delete(Account account) {
//implementation
}
#Override
public Account activate(AccountInfo) {
// implementation
}
}
and:
interface AccountState {
Account activate(AccountInfo);
Account delete(AccountInfo);
}
I know there must be a better implementation for this problem. Which other design patterns are suitable for this setup?
UPDATE
I have found a few interesting articles to read in the topic:
How to implement a FSM - Finite State Machine in Java
When you have more complex state handling
If I understood question correctly, then it is necessary to apply some action by its state.
If it is true, then we can use Factory pattern to get desired object which can execute some action. Mapping between state and action can be putted into HashTable.
So let's see an example of code. I will write via C#, but this code can be easily translated to Java because languages have many syntax similarities.
So we will have enum of statuses:
public enum Status
{
Active,
Deleted,
Foo
}
and states of AccountState
public abstract class AccountState
{
public abstract void ExecSomeLogic();
}
public class ActiveState : AccountState // "extends" instead of ":" in Java
{
public override void ExecSomeLogic()
{
}
}
public class DeletedState : AccountState // "extends" instead of ":" in Java
{
public override void ExecSomeLogic()
{
}
}
public class FooState : AccountState // "extends" instead of ":" in Java
{
public override void ExecSomeLogic()
{
}
}
Then we need mapper class of Status to their AccountState:
public class StatusToAccountState
{
public Dictionary<Status, AccountState> AccountStateByStatus { get; set; } =
new Dictionary<Status, AccountState>() // HashMap in Java
{
{ Status.Active, new ActiveState() },
{ Status.Deleted, new DeletedState() },
{ Status.Foo, new FooState() },
};
}
And then in your service you can use it like this:
void Delete(long id, Status status)
{
StatusToAccountState statusToAccountState = new StatusToAccountState();
AccountState accountState = statusToAccountState.AccountStateByStatus[status];
accountState.ExecSomeLogic();
}
If there are many logic to figure out what Status of object is, then you can create some class which will have just one responisibility of figuring out what state of object is:
public class StatusManager
{
public Status Get()
{
return Status.Active; // or something another based on logic
}
}
After doing this, your classes will correspond to the single responsibility principle of SOLID. Read more about single responsibility principle of SOLID here
Too many switch-/if-Statements indicate the code smell "Tool Abusers" (see M. Fowler "Refactoring"). Use the polymorphism mechanics to solve this.
https://refactoring.guru/smells/switch-statements
I develop a Android application for a Ble-Device and implement a Interface to listen on write, read and subscribe operations. I add all my listener instances to a List and trigger the Interface methods like this:
readWriteEvent = new BleDevice.ReadWriteEvent(true, status, characteristic.getValue());
for (ReadWriteListener listener : readWriteListener) {
listener.onEvent(readWriteEvent);
}
But the problem is, that all ReadWriteEvents get triggered who have an active listener. So is there some kind of identification where I can trigger a specific listener ? So that I can do something like this:
for (ReadWriteListener listener : readWriteListener) {
if (listener.getUuid() == characteristic.getUuid()) {
listener.onEvent(readWriteEvent);
}
}
Or is there a better solution for my problem ? This is how my Interface looks know:
public interface ReadWriteListener {
void onEvent(BleDevice.ReadWriteEvent event);
}
Use an abstract class instead:
public abstract class ReadWriteListener {
private int uid;
public ReadWriteListener(int uid) {
this.uid = uid;
}
public int getUid() {
return uid; //or just make uid final and public
}
public abstract void onEvent(BleDevice.ReadWriteEvent event);
}
This way, when you construct it, you can pass a UID and retrieve it, while the onEvent method remains abstract and necessary to implement. Of course, this means you can no longer implement the listener in a class that's already extending another class.
I'm trying to find a framework, or a nice way of implementing a way combining various components, similar to an electronics kit. This is so that it can be wired together using xml (e.g. Spring). I want the users to be able to string together different components without having to worry about Java.
The set up I'm thinking of would have something like the following:
public interface Input<T> {
public T getValue();
}
public interface Output<T> {
public void setValue(T value);
}
public class Wire<T> implements Input<T>, Output<T> {
private T value;
public T getValue() { return value; }
public void setValue(T value) { this.value = value ; };
}
And then components would be something like
public interface Component {
public void evaluate();
}
public class Multiplier implements Component {
private Input<Double> inA;
private Input<Double> inB;
private Output<Double> out;
public Multiplier(Input<Double> inA, Input<Double> inB, Output<Double> out) {
this.inA = inA;
this.inB = inB;
this.out = out;
}
public void evaluate() {
out.setValue(inA.getValue() * inB.getValue());
}
}
main() {
Wire inA = new Wire();
Wire squareOut = new Wire();
Component squarer = new Multiplier(inA, inA, output)
}
So you could tie outputs of one component into the input of another. I've toyed with the idea of the Wires knowing about what outputs they're connected to, so that they can call evaluate on their components... but I think it might be easier to keep a separate "clock" so that circular dependencies can be controlled.
It's not hard to implement, I'd just rather use a public library if there is one already out there. I've struggled to find one.
Any advice about implementing something similar, or what to do instead would be really helpful.
You are talking about Dependency Injection Framework.
Look at Spring, Google Guice or PicoContainer.
I want to avoid using tagged classes and big if-else blocks or switch statement and use polymorphism with a class hierarchy instead, which I believe is better practice.
For example, something like the below, where the choice of executed method is dependent only one one field of an object of type Actor.
switch(actor.getTagField())
{
case 1: actor.act1(); break;
case 2: actor.act2(); break;
[...]
}
would become
actor.act();
and the act method would be overridden in subclasses of Actor.
However, the most obvious way to decide at runtime which subclass to instantiate looks awfully similar to the original:
Actor newActor(int type)
{
switch(type)
{
case 1: return new Actor1();
case 2: return new Actor2();
[...]
}
}
so it seems like nothing has really been gained; the logic has just been moved.
What is a better way to do this? The only way I can come up with involved implementing a factory class for each subclass of Actor, but this seems rather cumbersome for such a simple problem.
Am I overthinking this? It just seems like there's no point making the original change if I just do pretty much the same thing elsewhere.
Question is "if" you need a factory. The factory is meant to manage the creation of instances an not so much the behavior of related instances.
Otherwise, you're just looking at basic inheritance. Something like..
class Actor{
public void act(){
System.out.println("I act..");
}
}
class StuntActor extends Actor {
public void act(){
System.out.println("I do fancy stunts..");
}
}
class VoiceActor extends Actor {
public void act(){
System.out.println("I make funny noises..");
}
}
To Use, you can just instantiate the type of actor you need directly.
Actor fred = new Actor();
Actor tom = new VoiceActor();
Actor sally = new StuntActor();
fred.act();
tom.act();
sally.act();
Output:
I act..
I make funny noises..
I do fancy stunts..
EDIT:
If you need to centralize the creation of the Actors..aka vis a Factory, you will not be able to get away from some kind of switching logic--in which case..i'll typically use an enumeration for readability:
public class Actor{
public enum Type{ REGULAR, VOICE, STUNT }
public static Actor Create(Actor.Type type){
switch(type) {
case VOICE:
return new VoiceActor();
case STUNT:
return new StuntActor();
case REGULAR:
default:
return new Actor();
}
}
public void act(){
System.out.println("I act..");
}
}
Usage:
Actor some_actor = Actor.Create(Actor.Type.VOICE);
some_actor.act();
Output:
I make funny noises..
Switch statements aren't pure evil. It's really duplication that you're looking to eliminate with better design. Often times you'll find the same switch statement show up in different (far away) places in your code - not necessarily doing the same thing, but switching on the same data. By introducing polymorphism, you pull those switches together as different methods of the same object.
This does two things, first it reduces several switches to one switch inside of a factory and it pulls together spread out logic that probably depends on similar data. That data will turn into member variables in your objects.
It's also worth noting that you don't always end up with a switch statement under the hood of your factory. Maybe you could scan the classpath at startup and build a HashMap of types that implement an interface. For example, consider an implementation of a socket protocol like SMTP. You could have objects named HeloCommand, MailFromCommand, etc... and find the right object to handle the message by matching the socket command to the class name.
I believe that you can do it with Abstract factory pattern...
This is a example:
abstract class Computer {
public abstract Parts getRAM();
public abstract Parts getProcessor();
public abstract Parts getMonitor();
}
class Parts {
public String specification;
public Parts(String specification) {
this.specification = specification;
}
public String getSpecification() {
return specification;
}
}
We have two class that extends Computer
class PC extends Computer {
public Parts getRAM() {
return new Parts("512 MB");
}
public Parts getProcessor() {
return new Parts("Celeron");
}
public Parts getMonitor() {
return new Parts("15 inches");
}
}
class Workstation extends Computer {
public Parts getRAM() {
return new Parts("1 GB");
}
public Parts getProcessor() {
return new Parts("Intel P 3");
}
public Parts getMonitor() {
return new Parts("19 inches");
}
}
And finally we have,
public class ComputerType {
private Computer comp;
public static void main(String[] args) {
ComputerType type = new ComputerType();
Computer computer = type.getComputer("Workstation");
System.out.println("Monitor: "+computer.getMonitor().getSpecification());
System.out.println("RAM: "+computer.getRAM().getSpecification());
System.out.println("Processor: "+computer.getProcessor().getSpecification());
}
public Computer getComputer(String computerType) {
if (computerType.equals("PC"))
comp = new PC();
else if(computerType.equals("Workstation"))
comp = new Workstation();
return comp;
}
}
When applying this pattern Delegation Event Model, is it correct to put ALL the code in the fire... methods and pass the parameters from the public method?
Like this
public void addBananas(Banana banana) {
fireBananaAdded(banana);
}
private void fireBananaAdded(Banana banana) {
//Create event etc and add banana to list here
}
Or should I have the add to list part in this example in the addBananas method instead? Because if I do it this way I will not have the opportunity to "attach" the banana object to the event-object which will be passed to the listeners, right?
I would put as much logic in addBanana() that is related to actually adding the Banana as I can.
When I'm done with addBanana(), I would call fireBananaAdded() which would generate the appropriate BananaAddedEvent and send it to the BananaAddedListeners (or just BananaListeners, which ever you have.)
To put the ADD logic in the FIRE method is simply, well, BANANAS!
public void addBananas(Banana banana) {
if(BananaHolder.hasRoom()) {
BananaHolder.add(banana);
fireBananaAdded(banana);
}
}
private void fireBananaAdded(Banana banana) {
BananaAddedEvent event = new BananaAddedEvent(banana);
for(BananaListener listener : listenersByType(Banana.class)) {
listener.bananaAdded(event);
}
}