Skip to main content
Code Review

Return to Question

Post Reopened by Sven Hohenstein, syb0rg, Community Bot, janos, 200_success
added 1331 characters in body
Source Link
cldfzn
  • 165
  • 7

What follows is a contrived example just trying to illustrate the point. MyMy main questions: FileWithSave handles its saving itself, but delegates it to a repository object. This allows implementation details to be available without being present in the API when saving (transpose this to a Mail sending API as well, available for send but not public). Is this OK in terms of OOP practices? Are there any maintainence gotchas I'm missing? Does it need reorganization?

package com.example.external;
public interface File {
 /**
 * Get the unique identifier.
 *
 * @return unique identifier.
 */
 String getId();
 /**
 * Get the file name.
 *
 * @return file name.
 */
 String getName();
 /**
 * Sets name for the file.
 *
 * @param name file name.
 */
 void setName(String name);
 /**
 * Get the file size.
 *
 * @return file size.
 */
 Long getSize();
}
package com.example.internal;
public class FileImpl implements File {
 // I don't want it in my public signature but I want it when I'm saving for some reason :(
 private Something somethingPrivate;
 private final String id;
 private final String name;
 private final Long size;
 public FileImpl(String id, Long size) {
 this.id = id;
 this.size = size;
 }
 public String getId() {
 return id;
 }
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 public Long getSize() {
 return size;
}
}
package com.example.external;
public interface FilingCabinet {
 /**
 * Get a file from the cabinet.
 *
 * @param id unique identifier.
 * @return file.
 */
 File get(String id);
 /**
 * Store a file in the cabinet.
 *
 * @param file.
 */
 void store(File file);
}

Without save client sample code:

package com.example.external;
public interface FileWithSave extends File {
 /**
 * Save the changes.
 */
 File store();
}
package com.example.internal;
public class FileWithSaveImpl implements FileWithSave {
 private Something somethingPrivate;
 private final PrivateFilingCabinetString repo;id;
 private Somethingfinal somethingPrivate;String name;
 private final Long size;
 private final PrivateFilingCabinet repo;
 public FileWithSaveImpl(String id, Long size, PrivateFilingCabinet repo) {
 this.id = id;
 this.size = size;
 this.repo = repo;
 }
 //@Override
 those other methods public String getId() {
 return id;
 }
 @Override
 public String getName() {
 return name;
 }
 @Override
 public void setName(String name) {
 this.name = name;
 }
  @Override
 public Long getSize() {
 return size;
 }
 @Override
 public void store() {
 repo.save(this);
 }
}
package com.example.external;
/**
 * Wraps PrivateFilingCabinet and injects PrivateFilingCabinet in FileWithSave object.
 */
public interface Secretary {
 /**
 * Get the file for someone.
 *
 * @param unique identifier.
 * @return file.
 */
 FileWithSave getFile(String id);
}
package com.example.internal;
public interface PrivateFilingCabinet {
 /**
 * Get a file from the cabinet.
 *
 * @param id unique identifier.
 * @return file.
 */
 FileWithSaveImpl get(String id);
 /**
 * Store a file in the cabinet.
 *
 * @param file.
 */
 void store(FileWithSaveImpl file);
}

With save client sample code:

What follows is a contrived example just trying to illustrate the point. My main questions: FileWithSave handles its saving itself, but delegates it to a repository object. This allows implementation details to be available without being present in the API when saving (transpose this to a Mail sending API as well, available for send but not public). Is this OK in terms of OOP practices? Are there any maintainence gotchas I'm missing? Does it need reorganization?

public interface File {
 /**
 * Get the unique identifier.
 *
 * @return unique identifier.
 */
 String getId();
 /**
 * Get the file name.
 *
 * @return file name.
 */
 String getName();
 /**
 * Sets name for the file.
 *
 * @param name file name.
 */
 void setName(String name);
 /**
 * Get the file size.
 *
 * @return file size.
 */
 Long getSize();
}
public class FileImpl implements File {
 // I don't want it in my public signature but I want it when I'm saving for some reason :(
 private Something somethingPrivate;
}
public interface FilingCabinet {
 /**
 * Get a file from the cabinet.
 *
 * @param id unique identifier.
 * @return file.
 */
 File get(String id);
 /**
 * Store a file in the cabinet.
 *
 * @param file.
 */
 void store(File file);
}

Without save sample code:

public interface FileWithSave extends File {
 /**
 * Save the changes.
 */
 File store();
}
public class FileWithSaveImpl implements FileWithSave {
 private final PrivateFilingCabinet repo;
 private Something somethingPrivate;
 public FileWithSaveImpl(PrivateFilingCabinet repo) {
 this.repo = repo;
 }
 // those other methods
 @Override
 public void store() {
 repo.save(this);
 }
}
/**
 * Wraps PrivateFilingCabinet and injects PrivateFilingCabinet in FileWithSave object.
 */
public interface Secretary {
 /**
 * Get the file for someone.
 *
 * @param unique identifier.
 * @return file.
 */
 FileWithSave getFile(String id);
}
public interface PrivateFilingCabinet {
 /**
 * Get a file from the cabinet.
 *
 * @param id unique identifier.
 * @return file.
 */
 FileWithSaveImpl get(String id);
 /**
 * Store a file in the cabinet.
 *
 * @param file.
 */
 void store(FileWithSaveImpl file);
}

With save sample code:

My main questions: FileWithSave handles its saving itself, but delegates it to a repository object. This allows implementation details to be available without being present in the API when saving (transpose this to a Mail sending API as well, available for send but not public). Is this OK in terms of OOP practices? Are there any maintainence gotchas I'm missing? Does it need reorganization?

package com.example.external;
public interface File {
 /**
 * Get the unique identifier.
 *
 * @return unique identifier.
 */
 String getId();
 /**
 * Get the file name.
 *
 * @return file name.
 */
 String getName();
 /**
 * Sets name for the file.
 *
 * @param name file name.
 */
 void setName(String name);
 /**
 * Get the file size.
 *
 * @return file size.
 */
 Long getSize();
}
package com.example.internal;
public class FileImpl implements File {
 // I don't want it in my public signature but I want it when I'm saving for some reason :(
 private Something somethingPrivate;
 private final String id;
 private final String name;
 private final Long size;
 public FileImpl(String id, Long size) {
 this.id = id;
 this.size = size;
 }
 public String getId() {
 return id;
 }
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 public Long getSize() {
 return size;
}
}
package com.example.external;
public interface FilingCabinet {
 /**
 * Get a file from the cabinet.
 *
 * @param id unique identifier.
 * @return file.
 */
 File get(String id);
 /**
 * Store a file in the cabinet.
 *
 * @param file.
 */
 void store(File file);
}

Without save client sample code:

package com.example.external;
public interface FileWithSave extends File {
 /**
 * Save the changes.
 */
 File store();
}
package com.example.internal;
public class FileWithSaveImpl implements FileWithSave {
 private Something somethingPrivate;
 private final String id;
 private final String name;
 private final Long size;
 private final PrivateFilingCabinet repo;
 public FileWithSaveImpl(String id, Long size, PrivateFilingCabinet repo) {
 this.id = id;
 this.size = size;
 this.repo = repo;
 }
 @Override
  public String getId() {
 return id;
 }
 @Override
 public String getName() {
 return name;
 }
 @Override
 public void setName(String name) {
 this.name = name;
 }
  @Override
 public Long getSize() {
 return size;
 }
 @Override
 public void store() {
 repo.save(this);
 }
}
package com.example.external;
/**
 * Wraps PrivateFilingCabinet and injects PrivateFilingCabinet in FileWithSave object.
 */
public interface Secretary {
 /**
 * Get the file for someone.
 *
 * @param unique identifier.
 * @return file.
 */
 FileWithSave getFile(String id);
}
package com.example.internal;
public interface PrivateFilingCabinet {
 /**
 * Get a file from the cabinet.
 *
 * @param id unique identifier.
 * @return file.
 */
 FileWithSaveImpl get(String id);
 /**
 * Store a file in the cabinet.
 *
 * @param file.
 */
 void store(FileWithSaveImpl file);
}

With save client sample code:

Post Closed as "Not suitable for this site" by RubberDuck, mjolka, SirPython, syb0rg, Brythan
edited tags
Link
cldfzn
  • 165
  • 7

API Design: Should Domain objects savingfor a public API be able to save/sendingsend themselves?

Source Link
cldfzn
  • 165
  • 7

API Design: Domain objects saving/sending themselves

What follows is a contrived example just trying to illustrate the point. My main questions: FileWithSave handles its saving itself, but delegates it to a repository object. This allows implementation details to be available without being present in the API when saving (transpose this to a Mail sending API as well, available for send but not public). Is this OK in terms of OOP practices? Are there any maintainence gotchas I'm missing? Does it need reorganization?

Without save:

public interface File {
 /**
 * Get the unique identifier.
 *
 * @return unique identifier.
 */
 String getId();
 /**
 * Get the file name.
 *
 * @return file name.
 */
 String getName();
 /**
 * Sets name for the file.
 *
 * @param name file name.
 */
 void setName(String name);
 /**
 * Get the file size.
 *
 * @return file size.
 */
 Long getSize();
}

Without save implementation:

public class FileImpl implements File {
 // I don't want it in my public signature but I want it when I'm saving for some reason :(
 private Something somethingPrivate;
}

Repository for File:

public interface FilingCabinet {
 /**
 * Get a file from the cabinet.
 *
 * @param id unique identifier.
 * @return file.
 */
 File get(String id);
 /**
 * Store a file in the cabinet.
 *
 * @param file.
 */
 void store(File file);
}

Without save sample code:

FilingCabinet cabinet = room.getFilingCabinet();
File file = cabinet.get("my-unique-id");
file.setName("my-new-name");
cabinet.store(file);

With save:

public interface FileWithSave extends File {
 /**
 * Save the changes.
 */
 File store();
}

With save implementation:

public class FileWithSaveImpl implements FileWithSave {
 private final PrivateFilingCabinet repo;
 private Something somethingPrivate;
 public FileWithSaveImpl(PrivateFilingCabinet repo) {
 this.repo = repo;
 }
 // those other methods
 @Override
 public void store() {
 repo.save(this);
 }
}

Wrapper class:

/**
 * Wraps PrivateFilingCabinet and injects PrivateFilingCabinet in FileWithSave object.
 */
public interface Secretary {
 /**
 * Get the file for someone.
 *
 * @param unique identifier.
 * @return file.
 */
 FileWithSave getFile(String id);
}

Repository injected in to FileWithSave and not part of the public API package:

public interface PrivateFilingCabinet {
 /**
 * Get a file from the cabinet.
 *
 * @param id unique identifier.
 * @return file.
 */
 FileWithSaveImpl get(String id);
 /**
 * Store a file in the cabinet.
 *
 * @param file.
 */
 void store(FileWithSaveImpl file);
}

With save sample code:

FileWithSave file = company.getSecretary().getFile("my-unique-id");
file.setName("my-new-name");
file.store();
lang-java

AltStyle によって変換されたページ (->オリジナル) /