Most of my classes have different behavior if they are client or server side. (client: gui, server: connection stuff) but they also have some common behavior. I want to know what's the best way to do this.
Example content of a class:
public class Example{
private void commonMethod(){
//common code
}
public void clientMethod(){
commonMethod()
//Client code
}
public void serverMethod(){
commonMethod()
//Server code
}
}
What i want:
1 method with some way to specify client or server
Readable code
What is allowed:
still have 3 private methods : server, common and client
What i want to avoid:
case (unless it is readable / short)
if
Things i was thinking of:
enums (to specify client and server) and a case (better then to use meaningless ints or booleans)
annotations (#clientside) (#serverside)
Edit:
My classes are loaded in by an api, an example client/server method would be init. so in my main class i need to run that method for all the classes that need initialization.
If I were you (and if I understand your needs) I would use a common interface implemented by a client and a server class, with an abstract class in the middle:
public interface Example {
public void method();
}
public abstract class AbstractExample implements Example {
#Override
public void method() {
common();
implMethod();
}
private void common() {
// common implementation
}
protected abstract void implMethod();
}
public class ExampleClientImpl extends AbstractExample {
#Override
protected void implMethod() {
// client implementation
}
}
public class ExampleServerImpl extends AbstractExample {
#Override
protected void implMethod() {
// server implementation
}
}
With this approach you can also split your classes in common/client/server packages or better modules.
Related
Let me explain my behaviour with the following example:
I've got two similar Address Classes, with three similar informations, but different method names.
Address
- setNr, setCode, setStreetname, setHabitants
OtherAddress
- setNumber, setPostalcode, setStreet, setSize
I'm using an Address-Typed Consumer, that manipulates data of "Address" element.
Now I want to use the same Consumer with "OtherAddress", because same manipulation shall be done, on the similar methods.
public class AddressManipulateConsumer implements Consumer<Address> {
#Override
public void accept(Address address) {
address.setNr("22");
address.setCode("12345");
address.setStreetname("examplestr.");
}
}
my aim is to avoid duplicate the class:
public class AddressManipulateConsumer implements Consumer<OtherAddress> {
#Override
public void accept(OtherAddress address) {
address.setNumber("22");
address.setPostalcode("12345");
address.setStreet("examplestr.");
}
}
What are the stepts or ways for solving it?
You can make use an adaptor for OtherAddress
class OtherAddressAdaptor extends Address {
OtherAddress hiddenObject;
OtherAddressAdaptor(OtherAddress hiddenObject) {...}
#Override
void setNr(String number) {
this.hiddenObject.setNumber(number);
}
// do the same thing for other methods
}
Now, instead of using an OtherAddress object, create an OtherAddressAdaptor from it, and use that instead.
I would suggest following the below steps:
1) Create an adapter of OtherAddresses ("OtherAddressAdapter") with function names similar as Address
2) Create a parent Interface AddressWrapper having these 4 functions and make OtherAddressAdapter and Address implement this interface
3) Create consumer like below:
public class AddressManipulateConsumer implements Consumer<AddressWrapper> {
Create an interface for the 3 common methods:
interface BasicAddress {
void setNumber(String number);
void setPostalcode(Stting code);
void setStreet(String street);
// getters too
}
Make Address and OtherAddress implement BasicAddress and rename the current methods to be aligned. They should use the same names anyway because they’re dealing with the same concepts.
Have the consumer accept BasicAddress:
public class AddressManipulateConsumer implements Consumer<BasicAddress> {
#Override
public void accept(BasicAddress address) {
address.setNumber("22");
address.setPostalcode("12345");
address.setStreet("examplestr.");
}
}
So lets assume I am having the following stuff defined:
public interface IExportTool {
void export(IReport iReport);
}
And then attempting to use it:
public class KibanaExporter implements IExportTool{
public void export(IReport kibana) {
kibana = (Kibana) kibana;
((Kibana) kibana).toJSON();
}
}
But there are also other classes which would again be doing something like that too:
public class MetricExporter implements IExportTool{
public void export(IReport metric) {
metric = (Metric) metric;
((Metric) metric).toJSON(); // might be something else here like toXML etc
}
}
Please note that both Kibana and Metric are implementing IReport<KibanaRow> and IReport<MetricRow> respectively, while the IReport interface looks like:
public interface IReport<T> {
void addRow(T row);
}
I don't like all this casting, this doesn't feel right nor gives me autocomplete, so any suggestion how to do it properly?
From what you've posted, it's clear that both Kibana and Metric are subtypes of IReport.
In that case, you can make the interface generic:
interface IExportTool<R extends IReport> {
void export(R iReport);
}
And then change the implementations in this fashion:
public class KibanaExporter implements IExportTool<Kibana>{
public void export(Kibana kibana) {
kibana.toJSON();
}
}
And:
public class MetricExporter implements IExportTool<Metric> {
public void export(Metric metric) {
metric.toJSON();
}
}
This version allows the compiler to understand and validate that only instances of subtypes of IReport will ever be passed to export(). Code using this will be validated by the compiler, such that MetricExporter().export() can only be called with an object of type Metric and KibanaExporter().export() with an object of type Kibana.
And with that, type casts are no longer needed.
I should use and name a design pattern for following problem:
I have separate interfaces: Basic, Complex. All classes implement Basic. Some of the classes implement Complex but they have to inherit from Abstract class.
I was thinking about decorator but I don't know if I'm right.
Code is in Java.
I think something like Builder design pattern can be good for this case:
first Create an interface for the Basic
public interface Basic{
public void basicOp();
}
second: create an interface for the Complex one:
public interface Complex{
public void complexOp();
public Basic basicOp();
}
Third: create required classes which implements basic interface:(Class2)
public class abstractBasicA implements Basic {
#Override
public void basicOp() { ... }
}
fourth: create abstract required classes for complex interface
public abstract class AbstractClassComplexA implements Complex{
#Override
public complexOp() { ... }
#Override
public abstract Basic basicOp(){...}
}
fifth: create all other classes which extends above abstract class(Class3, Class4, Class5).
I think you should go with decorator pattern and use composition. A Complex should have a Basic member, which could manage the Basic part of the Complex type.
Below a short example.
package main;
public class Main {
public static void main(String[] args) {
Basic basic = new BasicImpl();
basic.basicOp();
// main.BasicImpl.op()
Complex ca = new ConcreteComplexA(basic);
ca.basicOp();
ca.complexOp();
// main.BasicImpl.op()
// main.ConcreteComplexA.complex()
Complex cb = new ConcreteComplexB(basic);
cb.basicOp();
cb.complexOp();
// main.BasicImpl.op()
// main.ConcreteComplexB.complex()
}
}
interface Basic {
void basicOp();
}
interface Complex extends Basic {
void complexOp();
}
class BasicImpl implements Basic {
#Override
public void basicOp() {
System.out.println("main.BasicImpl.basicOp()");
}
}
abstract class AbstractComplex implements Complex {
private final Basic basic;
public AbstractComplex(Basic basic) {
this.basic = basic;
}
#Override
public void basicOp() {
basic.basicOp();
}
}
class ConcreteComplexA extends AbstractComplex {
public ConcreteComplexA(Basic basic) {
super(basic);
}
#Override
public void complexOp() {
System.out.println("main.ConcreteComplexA.complex()");
}
}
class ConcreteComplexB extends AbstractComplex {
public ConcreteComplexB(Basic basic) {
super(basic);
}
#Override
public void complexOp() {
System.out.println("main.ConcreteComplexB.complex()");
}
}
If you want clean subtypting, you have to enforce behavioral conformance, i.e. adhere to all the invariants of the type (and of its methods) your inheriting from, you need Basic to extend Complex, but that feels counter-intuitive very often. But only if Complex redefines/specializes the inherited methods.
Sometimes it is best to make use of composition instead of inheritance. So instead of relying on a lot of subclasses, pull out the behaviour in an independent structure and inject it. Design patterns that could be playing here would be strategy and dependency injection (inversion of control).
Deep class hierarchies are often a smell indicator and often you run into problems since Java doesn't support trades and you get code duplication if you need the same behavior in different classes that don't share the same ancestor.
Best explained by an example:
interface Plane {
public void flapsExtended();
public void engineFullThrottle();
public void takeOff();
public void landed();
}
class Spitfire implements Plane {
}
class P51Mustang implements Plane {
}
So far my code was doing a good job. But as WW2 ended we had never jets with retractable landing gear.
So I added a new class for F22 which would need to add retractLandingGear() and extendLandingGear between the takeOff and land phase.
example:
class F22 {
public void flapsExtended();
public void engineFullThrottle();
public void takeOff();
public void retractLandingGear();
public void extendLandingGear();
public void landed();
}
Now how can I plugging F22's with those legacy code ( and legacy planes :) ) ?
If you fully control all the code and are able to modify it, just modify the old classes so the new methods perform no-ops.
However, if you can't modify the old classes, you will have to make a new sub-interface with the extra methods and do instanceof checks to see which version of the interface the object you are working on uses and then cast accordingly.
This problem will be resolved in Java 8 when you can add default implementations to interfaces.
I have a Java generics question I was hoping someone could answer. Consider the following code:
public interface Event{}
public class AddressChanged implements Event{}
public class AddressDiscarded implements Event{}
public interface Handles<T extends Event>{
public void handle(T event);
}
I want to implement this Handles interface like this:
public class AddressHandler implements Handles<AddressChanged>, Handles<AddressDiscarded>{
public void handle(AddressChanged e){}
public void handle(AddressDiscarded e){}
}
But java doesn't allow implementing Handles twice using the Generic. I was able to accomplish this with C#, but cannot figure a workaround in java without using Reflection or instanceof and casting.
Is there a way in java to implement the Handles interface using both generic interfaces? Or perhaps another way to write the Handles interface so the end result can be accomplished?
Going after #Amir Raminfar, you can use visitor pattern
interface Event{
void accept(Visitor v);
}
interface Visitor {
void visitAddressChanged(AddressChanged a);
void visitAddressDiscarded(AddressDiscarded a);
}
class AddressChanged implements Event{
#Override
public void accept(Visitor v) {
v.visitAddressChanged(this);
}
}
class AddressDiscarded implements Event{
#Override
public void accept(Visitor v) {
v.visitAddressDiscarded(this);
}
}
class AddressHandler implements Visitor {
void handle(Event e){
e.accept(this);
}
public void visitAddressChanged(AddressChanged e){}
public void visitAddressDiscarded(AddressDiscarded e){}
}
You can't do that in Java. You can only implement one concrete realization of the same generic interface. I would do this instead:
public class AddressHandler implements Handles<Event>{
public void handle(Event e){
if(e instanceof AddressDiscarded){
handleDiscarded(e);
} else if(e instanceof AddressChanged){
handleChanged(e);
}
}
public void handleDiscarded(AddressDiscarded e){}
public void handleChanged(AddressChanged e){}
}
No, because different "concrete" generic types in Java compile to the same type. The actual interface your object will implement is:
public interface Handles {
public void handle(Event event);
}
And, obviously, you can't have two different methods with an identical signature...
AFAIK you cannot do that, because when compiling the source code in Java these will both boil down to handle(Event), making the method ambiguous.
The generic information is not available during runtime in Java, in contrast to C#. That is why there it works as you describe.
You will have to change the method names to make them unique, like handleAddressChanged and handleAddressDiscarded.
This is indeed one of the weak points of Java generics.
Unfortunately not. The usual solution (fat, ugly, fast) is to create one Handles interface (i.e. HandlesAddressChange, HandlesAddressDiscarded) and give each of them a different method (handleAddressChange(...), handleAddressDiscarded()).
That way, the Java runtime can tell them apart.
Or you can use anonymous classes.
It isn't allowed because Java erases generic signatures during compilation. The interface method will actually have the signature
public void handle(Object event);
So you have two choices. Either implement separate Handlers for different events:
public class AddressChangedHandler implements Handles<AddressChanged>{ /* ... */ }
public class AddressDiscardedHandler implements Handles<AddressDiscarded>{ /* ... */ }
or implement one handler for all but check the type of the incoming event:
public void handle(Event e){
if (e instanceof AddressChanged) {
handleAdressChanged(e);
}
else if (e instanceof AddressDiscareded) {
handleAdressDiscarded(e);
}
}
An implementation like this won't work due to the constraints of the java specification.
But if you're not afraid to use AOP or some sort of an IOC-Container you could use annotations for that. Than your Aspects or the container could manage the messaging infrastructure and call the methods you annotate.
First you have to create the annotations.
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface EventConsumer {}
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Handles{}
The you may annotate your class like that:
#EventConsumer
public class AddressHandler{
#Handles
public void handle(AddressChanged e){}
#Handles
public void handle(AddressDiscarded e){}
}
If you don't mind using a (small) library, here's one I wrote that solves your problem:
https://github.com/bertilmuth/requirementsascode
You'd build a model like this
Model.builder()
.on(AddressChanged.class).system(this::handleAddressChanged)
.on(AddressDiscarded.class).system(this::handleAddressDiscarded)
.build()
and run it.
How to do that exactly is described on the website.