I'm refactoring some code, abstracting functionality from a subclass to a helper class, but I found that I need methods from the superclass in the helper class.
I was wondering if there is a design pattern that can help me to do this. Or any other suggestions.
public class Notification(){
public void printMessage(String k, String str){
//Some code
}
}
public class NotificationImpl1 extends Notification(){
ErrorHelper helper = new ErrorHelper();
helper.showMessage("test");
}
public class ErrorHelper(){
public void showMessage(String msg){
// need to call printMessage() here
}
}
Thanks in advance.
public class ErrorHelper(){
Notification notification = null;
public ErrorHelper(Notification notification){
this.notification = notification;
}
public void showMessage(String k_str, String msg){
this.notification.printMessage(k_str, msg);
// need to call printMessage() here
}
}
public class Notification(){
public void printMessage(String k, String str){
//Some code
}
}
public class NotificationImpl1 extends Notification(){
public void method1() {
ErrorHelper helper = new ErrorHelper();
helper.showMessage("test", this);
}
}
public class ErrorHelper() {
public void showMessage(String msg, Notification notification){
// Change msg to necessary 2 parameters.
String k = getK(msg);
String str = getStr(msg);
notification.printMessage(k, str);
}
}
Related
I like to have a Drive class where all files and folders for a project are managed.
My first attempt was pretty easy like a lot of functions (most of them with arguments).
Now I try to make it more fancy because it became more and more annoying to have a lot of functions, in which the desired one can be found. To not have an XY-problem here, I start with my dream.
I like to construct the Drive class in a way, so that it is super easy to find a certain file or folder.
If you look in the main function, I can find every needed file by writing a point and look which subclasses/methods are proposed to continue, till I find it and add .str to it. At every point, only the subclasses/methods will be proposed which makes sense at this point.
It almost works! It is more complicated to write and maintain as the first approach, but If I use it very often, it could be worth it.
I can:
go into subfolders
go into subfolders with name inside the argument
But there is an error if I define a fixed-name-subfolder of a fluid-name-folder like in the code below.
Now my questions:
how can I change the code so the main Function doesn't show this error?
would you recommend a completely different approach to the "make it easy to find strings inside a huge list of strings via making collections inside collections... of strings"-problem?
package utilities;
public class Drive_draft {
private static final String fs = System.getProperty("file.separator");
public static final String str = System.getProperty("user.home").concat(fs);
public static class IeCreation {
public static final String str = Drive_draft.str.concat(".meetings").concat(fs);
public static class Abstract {
public static final String str = IeCreation.str.concat("Abstracts").concat(fs);
}
public static class Meeting {
public static final String str = IeCreation.str.concat("Ueberordnungen").concat(fs);
}
}
public static class MetsSIPs {
public static final String str = Drive_draft.str.concat("workspace").concat(fs).concat("metsSIPs").concat(fs);
public static class preSIPs {
public static final String str = MetsSIPs.str.concat("preSIPs").concat(fs);
}
public static class RosettaInstance {
private static class MaterialflowId {
public static String str;
private static class ProducerId {
public static String str;
private static class Abstract {
public static String str;
public static class Mets {
public static final String str = Abstract.str.concat("content").concat(fs).concat("ie1.xml");
}
}
private static class Meeting {
public static String str;
}
public static Abstract Abstract (String value) {
Abstract ret = new Abstract();
ProducerId.Abstract.str = str.concat(value).concat(fs);
return ret;
}
public static Meeting Meeting (String value) {
Meeting ret = new Meeting();
ProducerId.Meeting.str = str.concat(value).concat(fs);
return ret;
}
}
public static ProducerId ProducerId (String value) {
ProducerId ret = new ProducerId();
MaterialflowId.ProducerId.str = str.concat(value).concat(fs);
return ret;
}
}
public static MaterialflowId MaterialflowId (String value) {
MaterialflowId ret = new MaterialflowId();
MaterialflowId.str = str.concat(value).concat(fs);
return ret;
}
}
public static class Dev extends RosettaInstance {
public static final String str = MetsSIPs.str.concat("dev").concat(fs);
}
public static class Test extends RosettaInstance {
public static final String str = MetsSIPs.str.concat("test").concat(fs);
}
public static class Prod extends RosettaInstance{
public static final String str = MetsSIPs.str.concat("prod").concat(fs);
}
}
#SuppressWarnings("static-access")
public static void main(String[] args) {
System.out.println(Drive_draft.MetsSIPs.Dev.str);
System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").str);
System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("2").str);
System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").ProducerId("t").str);
System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").ProducerId("t").Abstract("est").str);
System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").ProducerId("t").Meeting("oast").str);
System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").ProducerId("t").Abstract("est").Mets.str); //Error: Mets cannot be resolved or is not a field
}
}
You can encode your "directory" structure with interfaces, with each interface declaring what the user can do next. Then the implementation can use a StringBuilder to just append the appropriate snippets and keep returning this.
// PathBuilderInterfaces.java
public class PathBuilderInterfaces {
public interface Buildable {
String build();
}
public interface Drive extends Buildable {
IeCreation ieCreation();
MetsSIPs metsSIPs();
}
public interface IeCreation extends Buildable {
String ieCreationAbstract();
String meeting();
}
public interface MetsSIPs extends Buildable {
RosettaInstance dev();
RosettaInstance test();
RosettaInstance prod();
}
public interface RosettaInstance extends Buildable {
MaterialFlowId materialFlowId(String value);
}
public interface MaterialFlowId extends Buildable {
ProducerId producerId(String value);
}
public interface ProducerId extends Buildable {
Abstract producerIdAbstract(String value);
String meeting(String value);
}
public interface Abstract extends Buildable {
String mets();
}
}
// PathBuilder.java
import static com.example.somepackage.PathBuilderInterfaces.*;
public class PathBuilder implements Drive, IeCreation, MetsSIPs, RosettaInstance, MaterialFlowId, ProducerId, Abstract{
private StringBuilder builder = new StringBuilder(str);
private static final String fs = System.getProperty("file.separator");
public static final String str = System.getProperty("user.home").concat(fs);
public static Drive drive() {
return new PathBuilder();
}
#Override
public String build() {
return builder.toString();
}
#Override
public IeCreation ieCreation() {
builder.append(".meetings").append(fs);
return this;
}
#Override
public MetsSIPs metsSIPs() {
builder.append("workspace").append(fs).append("metsSIPs").append(fs);
return this;
}
#Override
public RosettaInstance dev() {
builder.append("dev").append(fs);
return this;
}
#Override
public RosettaInstance test() {
builder.append("test").append(fs);
return this;
}
#Override
public RosettaInstance prod() {
builder.append("prod").append(fs);
return this;
}
#Override
public MaterialFlowId materialFlowId(String value) {
builder.append(value).append(fs);
return this;
}
#Override
public ProducerId producerId(String value) {
builder.append(value).append(fs);
return this;
}
#Override
public Abstract producerIdAbstract(String value) {
builder.append(value).append(fs);
return this;
}
#Override
public String meeting(String value) {
builder.append(value).append(fs);
return build();
}
#Override
public String mets() {
builder.append("content").append(fs).append("ie1.xml");
return build();
}
#Override
public String ieCreationAbstract() {
builder.append("Abstracts").append(fs);
return build();
}
#Override
public String meeting() {
builder.append("Ueberordnungen").append(fs);
return build();
}
}
Usage:
// in a main method somewhere
System.out.println(
PathBuilder.drive()
.metsSIPs()
.dev()
.materialFlowId("1")
.producerId("t")
.producerIdAbstract("est")
.mets());
I have enum like this:
public enum Email{
WELCOME,
LOGIN
}
EmailService has following method signature:
public void sendEmail(String from, String subject, String[] to, Map<String, String> props, String templateFileName)
I want to have API like this:
Email.WELCOME.send(from, subject, to, welcomeProp1, welcomeProp2....)
Email.LOGIN.send(from, subject, to, loginProp1, loginProp2....)
To acheve this I tried to add specific methods to enum fields:
public enum Email{
WELCOME{
public void send(String param1,String param2,String param3,String param4){
....
}
},
LOGIN{
public void send(String anotherParam1,String anotherParam2,String anotherParam3){
....
}
}
}
But I found out that I could not invoke this methods outside of enum. To acheve it I need to create abstract method and override in each enum value. But problem that signature of these methods are different and it is impossible to do it.
Any ideas?
You can use polymorphism for in such case. First of all, define some interface, for instance:
public interface Message {
}
Then you should add an abstract method to the enum:
public abstract void send(Message message);
After that, create two child classes - the first one is for WELCOME and the second one is for LOGIN:
class WelcomeMessage implements Message {
private String param1;
private String param2;
private String param3;
private String param4;
// constructor, getters
}
class LoginMessage implements Message {
private String anotherParam1;
private String anotherParam2;
private String anotherParam3;
// constructor, getters
}
Then add implementations of send() method:
public enum Email {
WELCOME {
public void send(Message message) {
WelcomeMessage wm = (WelcomeMessage) message;
....
}
},
LOGIN {
public void send(Message message) {
LoginMessage lm = (LoginMessage) message;
....
}
}
}
UPD.
#gstackoverflow mentioned that it's possible to invoke methods with "incorrect" implementation. I guess I know how to prevent this.
public enum Email {
WELCOME {
protected void sendInternal(Message message) {
WelcomeMessage wm = (WelcomeMessage) message;
....
}
protected Class<? extends Message> getSupportedClass() {
return WelcomeMessage.class;
}
},
LOGIN {
protected void sendInternal(Message message) {
LoginMessage lm = (LoginMessage) message;
....
}
protected Class<? extends Message> getSupportedClass() {
return LoginMessage;
}
};
public static void send(Message message) {
for (Email email : values()) {
if (email.getSupportedClass().equals(message.getClass()) {
email.sendInternal(message);
}
}
}
protected abstract void sendInternal(Message message);
protected abstract Class<? extends Message> getSupportedClass();
}
One solution is to make all the methods take exactly the same object, they just use different parameters from it.
class EmailDetails {
String param1;
String param2;
String param3;
String param4;
String anotherParam1;
String anotherParam2;
String anotherParam3;
}
public enum Email {
WELCOME {
public void send(EmailDetails details) {
System.out.println("Welcome!!");
}
},
LOGIN {
public void send(EmailDetails details) {
System.out.println("Log in!!");
}
};
public abstract void send(EmailDetails details);
}
public void test(String[] args) {
Email.WELCOME.send(new EmailDetails());
Email.LOGIN.send(new EmailDetails());
}
You will generally find that many of the fields are common to all uses.
Hi ive been reading on some similar topics here but none of them answer my question. Some say you cant even do this which is not a good thing since I cant finnish my course in that case.
Heres som simple code. Think of each block as a separate class.
public interface Interface {
void printMessage(String meddelande);
}
public class Model implements Interface {
String message = "hej!";
public static void main(String[] args) {
Model model1 = new Model();
View view1 = new View();
model1.printMessage(model1.message); //Ska jag anropa funktionen såhär ens?
}
public void printMessage(String str) {
}
}
public class View implements Interface {
printMessage(String str) {
}
}
So, how is it now possible to tel the view to print this string from the model class without the classes knowing about each other? Its not allowed to send a reference of the model-objekt to the view-object. ; (
Define an Interface:
public interface MyInterface {
void printMessage(String str);
}
Define a class that can trigger the notification:
public class ClassNotifier {
MyInterface mInterface;
public ClassNotifier(MyInterface mInterface) {
this.mInterface = mInterface;
}
public void triggerTheMsg(String msg) {
if (mInterface != null) {
mInterface.printMessage(msg);
}
}
}
Define a class that will be informed:
public class InformedClass implements MyInterface {
public static void main(String[] args) throws Exception {
InformedClass c = new InformedClass();
ClassNotifier cn = new ClassNotifier(c);
}
#Override
public void printMessage(String newMsg) {
System.out.println("A new msg is here: " + newMsg);
}
}
How does it works?:
this is named a callback parttern, the class ClassNotifier has a reference to the interface MyInterface, which is impl. by Informed class to, so every time the ClassNotifier calls the method printMessage, the method printMessage in the class Informed will be triggered too.
I advice you to use dependency injection, for example:
public class Model {
String message = "hej!";
Interface printer;
public void Model(Interface printer) {
printer = printer;
}
public static void main(String[] args) {
Model model1 = new Model(new View());
model1.printMessage(model1.message);
}
public void printMessage(String str) {
printer.printMessage(str);
}
}
before refactor:
public interface Service {
public void hello(Person p);
}
public class BlackPersonServiceImpl implements Service {
#Override
public void hello(Person p) {
//...
}
}
public class WhitePersonServiceImpl implements Service {
#Override
public void hello(Person p) {
//...
}
}
public class BeforeRefactor {
public static void main(String[] args) {
String str = args[0];
Person p = JSON.parseObject(str, Person.class);
Service service = getServiceFromSpringContainer();
service.hello(p);
}
private static Service getServiceFromSpringContainer() {
//...
return null;
}
}
after refactor:
public interface Service {
public void hello(String str);
}
public class WhitePersonServiceImpl implements Service {
#Override
public void hello(String str) {
Person person = JSON.parseObject(str, Person.class);
//do something to person...
//...
}
}
public class AfterRefactor {
public static void main(String[] args) {
String str = args[0];
Service service = getServiceFromSpringContainer();
service.hello(str);
}
private static Service getServiceFromSpringContainer() {
//...
return null;
}
}
That's what I want(I think "pull down" is not the "right" word to describe it...).
I tried "introduce parameter object" in eclipse, and it does not work.
There are many implementations of "Service". I dont want to change them one by one.
Is there a good way to solve this problem?
Thanks!
You can do it somewhat for a single class and a single method (although it's akward and a succession of small refactoring steps), but not across several types at the same time.
This question already has an answer here:
Methods in Enums [duplicate]
(1 answer)
Closed 8 years ago.
Right now, I have an enum for a variety of values, and I was wondering if there is any way I would be able to store a method in an enum. For example:
public enum myEnum{
one("first", callFirstMethod),
two("second", callSecondMethod),
three("last", callThirdMethod);
public String message;
public Method met;
myEnum(String m, Method meth){
message = m;
met = meth;
}
}
public class myMethods{
public void callFirstMethod(){
System.out.println("First!");
}
public void callSecondMethod(){
System.out.println("Second!");
}
public void callThirdMethod(){
System.out.println("Third!");
}
}
Then by using something like:
Method method = myEnum.one.callFirstMethod();
To call the method. Is something like this possible? I've tried playing around/looking around on google, and nothing is really turning up. Thank you for the help!
Use an interface and have the interface instance as the second enum parameter, or give it an abstract method that is implemented in the instance. For instance:
enum MyEnum {
ONE("first", new MyInterface() {
#Override
public void commonMethod() {
System.out.println("First!");
}
}) {
#Override
public void abstractEnumMethod() {
System.out.println("abstract enum meuthod, first!");
}
},
TWO("second", new MyInterface() {
#Override
public void commonMethod() {
System.out.println("Second!");
}
}) {
#Override
public void abstractEnumMethod() {
System.out.println("abstract enum meuthod, second!");
}
},
THREE("last", new MyInterface() {
#Override
public void commonMethod() {
System.out.println("Third!");
}
}) {
#Override
public void abstractEnumMethod() {
System.out.println("abstract enum meuthod, third!");
}
};
private String message;
private MyInterface myType;
private MyEnum(String m, MyInterface myType) {
message = m;
this.myType = myType;
}
public String getMessage() {
return message;
}
public MyInterface getMyType() {
return myType;
}
public void enumMethod() {
System.out.println(message);
}
public abstract void abstractEnumMethod();
}
interface MyInterface {
void commonMethod();
}
The answer all depends on what it's you want to achieve. For example, you could provide a common method within you enum and inspect the instance of the enum calling it...
public class TestEnum {
public static void main(String[] args) {
MyEnum.ONE.doStuff();
MyEnum.TWO.doStuff();
MyEnum.THREE.doStuff();
}
public enum MyEnum {
ONE("first"),
TWO("second"),
THREE("last");
public String message;
MyEnum(String m) {
message = m;
}
public void doStuff() {
System.out.println(name());
if (ONE.equals(this)) {
System.out.println("...Do stuff for one");
} else if (TWO.equals(this)) {
System.out.println("...Do stuff for two");
} else if (THREE.equals(this)) {
System.out.println("...Do stuff for three");
}
}
}
}
Which outputs...
one
...Do stuff for one
two
...Do stuff for two
three
...Do stuff for three