Nice way of factory method pattern with inheritance - java

Suppose I have following class hierarchy:
class abstract Parent{}
class FirstChild extends Parent {}
class SecondChild extends Parent {}
And I'd like to create DTO objects from each child:
class abstract ParentDTO {}
class FirstChildDTO extends ParentDTO{}
class SecondChildDTO extends ParentDTO{}
I think I need a factory method something like this:
ParentDTO createFrom(Parent source);
Is there any nice way to do this in Java without instanceof checks and if/else statements?
EDIT:
This factory method does not work:
public ParentDTO create(Parent source)
{
return _create(source);
}
private FirstChildDTO _create(FirstChild source)
{
return new FirstDTO();
}
private SecondChildDTO _create(SecondChild source)
{
return new SecondDTO();
}
private ParentDTO _create(Parent source)
{
return new ParentDTO();
}
It only generates ParentDTOs and here is why:
Parent p = new FirstChild();
System.out.println(factory.create(p)); //ParentDTO
FirstChild f = new FirstChild();
System.out.println(factory.create(f)); //FirstChildDTO

If you insist on using a factory for DTO creation you can use simple method overloading. Example follows:
public class Factory {
public ParentDTO createDTO(Parent parent) {
return new ParentDTO();
}
public FirstChildDTO createDTO(FirstChild firstChild) {
return new FirstChildDTO();
}
public SecondChildDTO createDTO(SecondChild SecondChild) {
return new SecondChildDTO();
}
}
public class Parent {
}
public class FirstChild extends Parent {
}
public class SecondChild extends Parent {
}
public class ParentDTO {
#Override
public String toString() {
return this.getClass().getSimpleName();
}
}
public class FirstChildDTO extends ParentDTO {
#Override
public String toString() {
return this.getClass().getSimpleName();
}
}
public class SecondChildDTO extends ParentDTO {
#Override
public String toString() {
return this.getClass().getSimpleName();
}
}
public class App {
public static void main(String[] args) {
Factory factory = new Factory();
ParentDTO parentDTO = factory.createDTO(new Parent());
System.out.println(parentDTO);
FirstChildDTO firstChildDTO = factory.createDTO(new FirstChild());
System.out.println(firstChildDTO);
SecondChildDTO secondChildDTO = factory.createDTO(new SecondChild());
System.out.println(secondChildDTO);
}
}
Running the App as Java application in my IDE outputs:
ParentDTO
FirstChildDTO
SecondChildDTO

That's quite a complex question. I'd resolve this in few steps.
Parent class should have some kind of interface that would allow your factory to recognize, what data should your DTO object contain, like this (in PHP language):
class Parent
{
abstract function getDataFields();
}
class FirstChild extends Parent
{
function getDataFields()
{
return ['id' => $this->id, 'name' => $this->name, 'email' => $this->email];
}
}
class SecondChild extends Parent
{
function getDataFields()
{
return ['id' => $this->id, 'brand' => $this->brand, 'model' => $this->model];
}
}
Now, you only need a single factory, AND i would use a single class for DTO too, since you know what subclass of Parent
class DTOFactory
{
function createFromParent(Parent $parent)
{
return new DTO($parent);
}
}
class DTO
{
private $fields = [];
function __construct(Parent $parent)
{
foreach ($parent->getDataFields() as $field => $value) {
$this->fields[$field] = $value
}
}
function __get($field)
{
return $this->fields[$field];
}
}
Of course, there are a lot of ways to make DTO's in various languages, i can't cover this in detail, that's up to you.
You could do your factory method static, but if you want to avoid that, you have to use Dependency Injection of some sorts:
class MyController
{
private $dtoFactory;
function __construct(DTOFactory $factory)
{
$this->dtoFactory = $factory;
}
function returnDTOAction()
{
$object = new FirstChild(); // or some other way to get your child;
return $this->factory->createFromParent($object);
}
}
class DIContainer
{
private $instances = [];
function get($className)
{
if (!is_object($this->instances[$className]) {
$this->instances[$className] = new $className;
}
return $this->instances[$className] = new $className;
}
}
$container = new DIContainer;
$controller = new MyController($container->get('DTOFactory'));
This is a very simple example of DI Container, better examples have automatic dependency resolution, so you simply call them like $container->get('MyController'); and get a class with automatically resolved dependencies, but i won't go into further detail on this, since their implementation is heavily language-dependent, and i only stuck with a basic one.
Anyways, hope this helps. If you need some clarifications - feel free to comment.

You can code the factory method directly into the model class and utilize Java's covariant return type to return the correct type of DTO, for example:
public class Parent {
public ParentDTO createDTO() {
return new ParentDTO();
}
}
public class FirstChild extends Parent {
#Override
public FirstChildDTO createDTO() {
return new FirstChildDTO();
}
}
public class SecondChild extends Parent {
#Override
public SecondChildDTO createDTO() {
return new SecondChildDTO();
}
}

Related

Choosing between extended classes inside constructor

I am writing a java (processing) library for unexperienced students, and am looking for the best architecture for implementing it.
Initialization of an object should be as close as possible to this:
myObject = new General("type1");
Such that myObject will become an instance of Type1 which extends General:
class General {
public General() {}
}
class Type1 extends General {
public Type1() {}
}
class Type2 extends General {
public Type1() {}
}
As far as I know, this isn't possible (choosing between extended classes during initialization), but I'm looking for the closest solution possible.
So far, my best solution is to make a static initializer inside General:
class General {
...
static General init (String type) {
General temp;
if (type.equals("type1") {
temp = new Type1();
}
...
return temp;
}
and the initialization is:
General myObject;
myObject = General.init("type1");
This is far from ideal...
thanks.
you can make a factory class that manages initialization.
instead of doing it inside the parent.
// Empty vocabulary of actual object
public interface IPerson
{
string GetName();
}
public class Villager : IPerson
{
public string GetName()
{
return "Village Person";
}
}
public class CityPerson : IPerson
{
public string GetName()
{
return "City Person";
}
}
public enum PersonType
{
Rural,
Urban
}
/// <summary>
/// Implementation of Factory - Used to create objects.
/// </summary>
public class Factory
{
public IPerson GetPerson(PersonType type)
{
switch (type)
{
case PersonType.Rural:
return new Villager();
case PersonType.Urban:
return new CityPerson();
default:
throw new NotSupportedException();
}
}
}
The State design pattern can be a solution here. Rather than the constructor argument changing the type of the object (which isn't possible) it can set a field of the object, to make it behave as if its type is different.
package stackoverflow.questions;
public class Main {
private interface MyInterface {
String foo();
int bar();
}
private static class Type1 implements MyInterface {
#Override public String foo() { return "lorem ipsum "; }
#Override public int bar() { return 6; }
}
private static class Type2 implements MyInterface {
#Override public String foo() { return "dolor sit amet"; }
#Override public int bar() { return 7; }
}
public static class General {
private final MyInterface type;
public General(String type) {
try {
this.type = (MyInterface) Class
.forName("stackoverflow.questions.Main$" + type)
.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("Invalid type: " + type);
}
}
public String method1() { return type.foo(); }
public int method2() { return type.bar(); }
}
public static void main(String... args) {
General one = new General("Type1");
General two = new General("Type2");
System.out.println(one.method1() + two.method1());
System.out.println(one.method2() * two.method2());
}
}

Handle duplicate code in concrete implementations of an interface in Spring boot application

I am working on a spring boot application, where I have an interface I as follows:
public interface I {
String getType();
void f1();
}
There are two classes implementing interface I as follows:
#Component
class A implements I {
private final MyRepo1 myRepo1;
private final Helper helper;
public A(MyRepo1 myRepo1, Helper helper) {
this.myRepo1 = myRepo1;
this.helper = helper;
}
#Override
public String getType() {
return "type1";
}
#Override
public void f1(String type) {
int response = helper.f1(type);
if(response != -1) {
return;
}
//Add type1 specific handling here
}
}
One more class B implementing interface I as follows:
#Component
class B implements I {
private final MyRepo2 myRepo2;
private final Helper helper;
public B(MyRepo2 myRepo2, Helper helper) {
this.myRepo2 = myRepo2;
this.helper = helper;
}
#Override
public String getType() {
return "type2";
}
#Override
public void f1(String type) {
int response = helper.f1(type);
if(response != -1) {
return;
}
//Add type2 specific handling here
}
}
Helper is as follows:
#Component
class Helper {
public int f1(String type) {
...
}
}
I have a factory class as follows, that is used to fetch an object of the appropriate type:
#Component
public class ServiceFactory {
private final Map<String, I>
typeToClassMap = new HashMap<>();
public ServiceFactory(List<I> components) {
for(I component : components) {
typeToClassMap.put(component.getType(), component);
}
}
}
This ServiceFactory is basically used to get objects according to the type.
Now, the problem is, here for sake of simplicity I have just shown two classes implementing the interface. But actually, I have a lot more classes than this, implementing the interface I.
Some of the classes may have the same implementation of f1(), resulting in duplicate code.
I cannot make f1() as the default method in interface I as this requires the dependent bean.
I cannot understand what is the best way to handle this.
Could anyone please help here?

How to access super class' super class in a Sonar Custom rule?

I'm writing a custom rule that will check whether the class under analysis is extending a type.
For example:
class Bus {
}
class Transport {
}
class PublicTransport extends Transport {
}
class Bus should extend class Transport or a sub class of Transport.
public class EnsureSuperClassRule extends IssuableSubscriptionVisitor {
final String SUPER_CLASS = "common.service.SuperService";
#Override
public List<Tree.Kind> nodesToVisit() {
return ImmutableList.of(Tree.Kind.CLASS);
}
#Override
public void visitNode(Tree tree) {
ClassTree classTree = (ClassTree) tree;
String className = classTree.simpleName().name();
if (className.endsWith("Service")) {
if(classTree.superClass() == null) {
return false;
}
if (!SUPER_CLASS.equals(localClassTree.superClass().symbolType().fullyQualifiedName())) {
reportIssue(tree, String.format("The class should extend SuperService or a class of type SuperService"));
}
}
}
}
}
How can I get the information related to superclass of the superclass?
You can simply call
Class superClassOfSuperClass = this.class().getSuperClass();
superClassOfSuperClass.method().invoke(this);
I'm not sure with your above example as there is a few typo's or misunderstanding with inheritance
You can collect all super classes until java.lang.Object was reached like so:
#Override
public void visitNode(Tree pTree) {
final ClassTree classTree = (ClassTree) pTree;
final Set<String> superclasses = new HashSet<>();
Type currentSuperclass = classTree.symbol().superClass();
while (currentSuperclass != null) {
superclasses.add(currentSuperclass.fullyQualifiedName());
currentSuperclass = currentSuperclass.symbol().superClass();
}
// ... do something with superClasses
super.visitNode(pTree);
}
#Override
public List<Kind> nodesToVisit() {
return ImmutableList.of(Tree.Kind.CLASS);
}
(Tested with sonar-java-plugin 6.3.0 and sonar-plugin-api 8.2.0)

data access object pattern with abstract factories, creation over generic types

I'm developing a database application for android devices.
First thing I need to do is creating the data access layer.
For this I want to use DAO-Pattern with abstract factories.
For all DAOs i have one Interface witch contains the declaration that all data object needs to implement. (in my case: IDataObject)
The specific DAOs are all represented by its own interface, extending the base interface of all DAOs.
base interface:
public interface IDataObject {
public IDataId getId();
public void write() throws MyDataWriteException;
public void validate() throws MyDataValidException;
}
a extensions:
public interface IDataSample1 extends IDataObject {
public void setNotice(String notice);
public String getNotice();
public void setDate(Date date);
public Date getDate();
}
To create an data object I want use abstract to use abstract factories, something like:
public interface IDataFactory<Template extends IDataObject> {
public List<Template> getAll();
public Template get(IDataId id);
public List<Template> getList(DataAccessArgument arg);
public List<Template> getList(List<DataAccessArgument> argList);
}
and the implementation:
public class DataSample1Fac implements IDataFactory<IDataSample1> {
public DataSample1Fac () {
}
public List<IDataSample1> getAll() {
return null;
}
public IDataSample1 get(IDataId id) {
return null;
}
public List<IDataSample1> getList(DataAccessArgument arg) {
return null;
}
public List<IDataSample1> getList(List<DataAccessArgument> argList) {
return null;
}
}
I don't get any error so far, but now I want to implement an factory builder:
public class DataFactoryBuilder {
private DataFactoryBuilder() {
}
public static<T extends IDataObject> IDataFactory<T> getFactory(){
if (T instanceof IDataSample1)
return new DataSample1Fac();
return null;
}
}
I get following errors(line 8):
T cannot be resolved to a variable
and (line 9)
Type mismatch: cannot convert from DataSample1Fac to IDataFactory<T>
Don't know how to fix this, any suggestions?
I would refactor Your's DataFactoryBuilder to something like that:
class DataFactoryBuilder {
private DataFactoryBuilder() {
}
public static IDataFactory<? extends IDataObject> getFactory(Class<? extends IDataObject> clazz){
if (IDataSample1.class.isAssignableFrom(clazz)) {
return new DataSample1Fac();
}
return null;
}
}
I got following solution:
public static <T extends IDataObject> IDataFactory<T> getFactory(Class<T> type) {
if (IDataSample1.class.isAssignableFrom(type)) {
DataSample1Facfac = new DataSample1Fac();
return (IDataFactory<T>) fac;
}
}
but i get an warning on: return (IDataFactory) fac;
Type safety: Unchecked cast from DataSample1Fac to IDataFactory<T>
I think that is not a problem, I just have to supress it

Instantiating generic class and implementing generic interface

I have this class:
public DrawItem {
protected String getSeperator() {
return "";
}
.......
// some other methods
}
I've another class which extends DrawItem.
public DrawNumber extends DrawItem {
#Override
protected String getSeperator() {
return "-";
}
}
Now, in a generic class CombinationGenerator<E>, I'm trying to instantiate objects of DrawItem/DrawNumber. As instantiating a generic type is not possible in java (like new E(...)), I've created a Factory interface according to this answer.
public interface DrawItemFactory<E> {
E create(...);
}
Then in the CombinationGenerator<E> class,
public class CombinationGenerator<E> {
DrawItemFactory<E> factory;
public CombinationGenerator<E>(DrawItemFactory<E> factory) {
this.factory = factory;
}
public List<E> generate() {
......
list.add(factory.create(...));
......
}
}
And now the DrawNumber class implements DrawItemFactory<DrawItem> interface.
public DrawItem implements DrawItemFactory<DrawItem> {
protected String getSeperator() {
return "";
}
#Override
public DrawItem create(...) {
return new DrawItem(...);
}
.......
// some other methods
}
And I can create CombinationGenerator<DrawItem> class.
DrawItem drawItem = new DrawItem(...);
CombinationGenerator<DrawItem> generator = new CombinationGenerator<DrawItem>(drawItem);
List<DrawItem> combinations = generator.generate();
So far, everything is fine. But when I try to create a DrawNumber class like this,
public DrawNumber implements DrawItemFactory<DrawNumber> {
....
}
It gives me the following error:
The interface DrawItemFactory cannot be implemented more than once with different arguments: DrawItemFactory<DrawItem> and DrawItemFactory<DrawNumber>
I've tried this solution but I got the same error. Is there any other way to do this?
Instead of using all those factories you could do something like this:
public class CombinationGenerator<E> {
E instance;
public CombinationGenerator(Class<E> clazz) {
Constructor<?> con = clazz.getConstructor();
this.instance = (E) con.newInstance();
}
}
...
CombinationGenerator<DrawNumber> cg = new CombinationGenerator<DrawNumber>(DrawNumber.class);
According to #JB Nizet's comment, I've solved the problem by creating two separate factory classes like this:
public interface ItemFactory<E> {
E create(int[] values);
public static class DrawItemFactory implements ItemFactory<DrawItem> {
#Override
public DrawItem create(int[] values) {
return new DrawItem(values);
}
}
public static class DrawNumberFactory implements ItemFactory<DrawNumber> {
#Override
public DrawNumber create(int[] values) {
return new DrawNumber(values);
}
}
}
In the CombinationGenerator,
public class CombinationGenerator<E> {
ItemFactory<E> factory;
public CombinationGenerator<E>(ItemFactory<E> factory) {
this.factory = factory;
}
public List<E> generate() {
......
list.add(factory.create(...));
......
}
}
And instantiated CombinationGenerator like this:
DrawNumber drawNumber = new DrawNumber();
CombinationGenerator<DrawNumber> generator = new CombinationGenerator<DrawNumber>(new ItemFactory.DrawNumberFactory());
List<DrawNumber> combinations = generator.generate();

Categories

Resources