I am trying to solve a design problem with design patterns. Now that I have the basics I am fairly sure that I overcomplicated it a lot. I seem to have multiple empty interfaces, and I probably could do with less with a different design. Also I'm not sure if future developers on the project will have an easy time figuring out this tangle.
I've made a mockup of the structure of the classes. The example is dumbed down to two service types (cf BaseAnimalService extensions), in the project there are more. There are also more BaseStrategy implementations.
At first I want do differentiate between a context for a CatService or DogService. This is done using a Map in the BaseStrategy class, which has the BaseAnimalService as value to enable polymorphism between the Cat/DogService. Based on the generic type of the BaseStrategy, implemented in the Dog/CatStrategy a different configurationMap is used, which in turn, based on the type of the criteria, loads one or the other implementation of the Dog/CatService.
The configuration maps are defined in the spring.xml file.
Since the Dog/CatService both implement an extra interface, cf. SomeOtherCat/DogService, which is external to my design, the Dog/CatService both have have empty interfaces too. SomeOtherCatService and SomeOtherDogService aren't related and aren't editable so I can't use them polymorphically, which is the reason for the Base/Cat/DogService interfaces.
I thought about making the BaseStrategy a StrategyFactory which returns a Cat/DogStrategy which in turn checks the type of the criteria for which BaseAnimalService to use. But since both these strategies use the same logic for their strategies, this would mean I would have to create another base class.
What do you think? Any suggestions on what would be a better design for this problem? Or any improvements to the current one?
class BaseStrategy<T extends BaseAnimalService> {
private ContextService contextService;
private Map<String, BaseAnimalService> configurationMap;
T getService() {
return configurationMap.get(contextService.getCurrentContext());
}
}
interface BaseAnimalService {
//empty
}
interface DogService extends BaseAnimalService {
//empty
}
interface CatService extends BaseAnimalService {
//empty
}
class DogStrategy extends BaseStrategy<DogService> {
//empty
}
class CatStrategy extends BaseStrategy<CatService> {
//empty
}
class BritishShortHairServiceImpl implements CatService, SomeOtherCatService {
#Override //source: SomeOtherCatService, same for other implementations below
void pur() {
//pur
}
}
class LionServiceImpl implements CatService, SomeOtherCatService {
#Override
void pur() {
//pur
}
}
class PitBullServiceImpl implements DogService, SomeOtherDogService {
#Override
void wagTail() {
//wag tail
}
}
class ChihuahuaServiceImpl implements DogService, SomeOtherDogService {
#Override
void wagTail() {
//wag tail
}
}
class CatPerson {
private BaseStrategy<CatService> catStrategy;
void pet() {
catStrategy.getService().pur();
}
}
class DogPerson {
private BaseStrategy<DogService> dogStrategy;
void feed() {
dogStrategy.getService().wagTail();
}
}
Relevant spring.xml snippet:
<bean id="baseStrategy" abstract="true"
class="com.animals.services.BaseStrategy">
<property name="contextService" ref="contextService"/>
</bean>
<bean id="catServiceStrategy"
class="com.animals.services.CatStrategyImpl"
parent="baseStrategy">
<property name="strategyConfigurationMap">
<map>
<entry key="CONTEXT1" value-ref="britishShortHairService"/>
<entry key="CONTEXT2" value-ref="lionService"/>
</map>
</property>
</bean>
<bean id="dogServiceStrategy"
class="com.animals.services.DogStrategyImpl"
parent="baseStrategy">
<property name="strategyConfigurationMap">
<map>
<entry key="CONTEXT1" value-ref="pitbullService"/>
<entry key="CONTEXT2" value-ref="chihuahuaService"/>
</map>
</property>
</bean>
I am not familiar with Spring or its Context Service model, so I am approaching this question from a general, language-independent OOP perspective.
In my opinion you need to be thinking about ways that you can pass configurations through the constructor (dependency injection) rather than switching based on maps. You need more "has a" relationships (composition) and less "is a" relationships (inheritance).
An AnimalService can take an animal object as an argument to the constructor. We can say that an AnimalFeedbackBehavior must include methods for positiveFeedback(), neutralFeedback(), and negativeFeedback() -- but how those methods are implemented can vary from animal to animal. A Cat would purr() in response to a positive interaction but a Dog would wagTail().
An AnimalOwner can feed() any animal and trigger AnimalFeedbackBehavior.positiveFeedback(). The AnimalOwner does not need to know what that behavior does behind the scenes. It does not even need to know what species of animal it has. All it needs to know is that this method exists.
interface AnimalFeedbackBehavior {
positiveFeedback(): void;
neutralFeedback(): void;
negativeFeedback(): void;
}
class AnimalOwner {
private animal: AnimalFeedbackBehavior;
// pass animal instance to the constructor
constructor( animal: AnimalFeedbackBehavior) {
this.animal = animal;
}
// trigger positive feedback when feeding
feed() {
this.animal.positiveFeedback();
}
}
class Cat implements AnimalFeedbackBehavior {
purr() {
//do something
}
positiveFeedback() {
this.purr();
}
/* ... rest of class ... */
}
Typescript Playground Link
Here we assumed that feed is always a positive interaction. But what if we want different animals to have different reactions to the same interactions? chase() might be positive for a Dog but negative for a Cat. A naïve approach would be to switch the feedback based on a map. But an ideal design allows for maximum abstraction where the AnimalOwner doesn't need to know anything about the animal types.
Let's try a totally different setup.
If you are dealing with a small set of behaviors, we could require that the animal has a response for each behavior, rather than positive/neutral/negative.
interface AnimalBehavior {
feedResponse(): void;
chaseResponse(): void;
}
But this could get unwieldy quickly. We could define an animal with a respond method that responds to some sort of generic action object. In the implementation, it can do something in response to the action or just ignore it.
This setup also makes the composition of multiple overriding behaviors more intuitive since we can go through a chain of respond functions until one handles it. We want to know it there was a response or not so we need to return something from the response function. If it's basically void then we can return a boolean flag that's true if it responded. If a response should return a value than you would return either that value or undefined.
interface Action {
type: string;
}
// we may want to attach some sort of data
interface ActionWithData<T> extends Action {
type: string;
data: T;
}
interface AnimalBehavior {
respond( action: Action ): string | undefined;
}
class Animal implements AnimalBehavior {
// an animal has an array of behavior responders
// as written, the earlier behaviors in the array override later ones
private behaviors: AnimalBehavior[];
// can instantiate an animal with multiple behaviors
constructor( behaviors: AnimalBehavior[] = [] ) {
this.behaviors = behaviors;
}
// can also add behaviors after the fact
public addOverride( behavior: AnimalBehavior ) {
this.behaviors = [behavior, ...this.behaviors];
}
// loop through behaviors until one responds
public respond (action: Action): string | undefined {
for ( let element of this.behaviors ) {
// could be a response or might be undefined
const response = element.respond(action);
if ( response ) {
return response;
}
}
// could do something here if no behaviors responded
return undefined;
}
}
class AnimalOwner {
private animal: AnimalBehavior;
// pass animal instance to the constructor
constructor( animal: AnimalBehavior) {
this.animal = animal;
}
// animal can respond to the feed action, or not
feed(): string | undefined {
return this.animal.respond({type: 'feed'});
}
chase(): string | undefined {
return this.animal.respond({ type: 'chase' });
}
}
These implementations feel sloppy at the moment. Right now none of them use this so it's pointless to use a class. But just to give you an idea:
class DogBehavior implements AnimalBehavior {
respond(action: Action): string | undefined {
switch (action.type) {
case 'feed':
return "Wag Tail";
case 'chase':
return "Run Around";
default:
return undefined;
}
}
}
class PuppyBehavior implements AnimalBehavior {
respond(action: Action): string | undefined {
switch (action.type) {
case 'feed':
return "Jump";
default:
return undefined;
}
}
}
class ChihuahuaBehavior implements AnimalBehavior {
respond(action: Action): string | undefined {
switch (action.type) {
case 'feed':
return "Yip";
default:
return undefined;
}
}
}
Both the Animal composition and the individual behaviors implement AnimalBehavior, so an AnimalOwner can take a DogBehavior directly or it can take an Animal composed of a DogBehavior and some other behaviors.
const owner1 = new AnimalOwner(new DogBehavior());
let res = owner1.feed(); // is "Wag Tail"
The order matters. If we have a chihuahua puppy, we need to decide whether ChihuahuaBehavior overrides PuppyBehavior or vice-versa.
// prioritizes puppy
const owner2 = new AnimalOwner(new Animal([new PuppyBehavior(), new ChihuahuaBehavior(), new DogBehavior()]));
res = owner2.feed(); // is "Jump" from PuppyBehavior
res = owner2.chase(); // is "Run Around" from DogBehavior because not overwritten
// prioritizes chihuahua
const owner3 = new AnimalOwner(new Animal([new ChihuahuaBehavior(), new PuppyBehavior(), new DogBehavior()]));
res = owner3.feed(); // is "Yip" from ChihuahuaBehavior
Typescript Playground Link
Related
I've got a top-level Controller object that is holding a reference to three objects (MyObject). I'd like to position these precisely on the page at any time, but I would like each object to also be editable, and I'm not really sure how to do that.
So far, I've got a class that extends ItemFragment and displays my individual items, like this:
class MyObjectFragment(o: MyObject) : ItemFragment<MyObject>() {
override val root = hbox {
...
}
}
Meanwhile, I have a top-level View with a reference to my controller, like this:
class TopLevelView : View() {
val controller = TopLevelController()
override val root = hbox {
add(MyObjectFragment(controller.myObject1))
...
add(MyObjectFragment(controller.myObject2))
...
add(MyObjectFragment(controller.myObject3))
}
}
And right now, all I have for the top level controller is this:
class TopLevelController() : Controller() {
val myObject1 = MyObject()
val myObject2 = MyObject()
val myObject3 = MyObject()
}
I'm trying to figure out what I need to do to wrap these objects as observable values. My first attempt was to add something like this to the init method of MyObjectFragment:
class MyObjectFragment(o: MyObject) : ItemFragment<MyObject>() {
init {
itemProperty.bind(o)
}
...
}
However, that method only takes an ObservableValue<MyObject>. What is the best way to get that to tie all of this together?
You can create an observable list of your objects like so:
class TopLevelController() : Controller() {
val myObjects = FXCollections.observableArrayList<MyObject>(MyObject(), MyObject(), MyObject())
}
Then in your TopLevelView, you can bind this list to a layout node's children property, and inflate the proper Fragment for each object:
class TopLevelView : View() {
val controller = TopLevelController()
override val root = hbox {
bindChildren(controller.myObjects) {
MyObjectFragment(it).root
}
}
}
I'll admit your requirements seem a little vague to me without more information. It'd be helpful to know more of what you want from the item fragments. Are they going to be in a list view or table? Or something more dynamic? And how exactly would they be editing? Would there be a save button or would you expect any input to commit those changes immediately?
import tornadofx.*
class MyObject() {
//val someProperty = SimpleObjectProperty<Something>()
//var some by someProperty
}
class MyObjectModel(myObject: MyObject? = null) : ItemViewModel<MyObject>(myObject) {
//val someBinding = bind(MyObject::someProperty)
}
class MyObjectFragment : ItemFragment<MyObject>() {
val model: MyObjectModel by inject()
override val root = hbox {
label("This is an MyObject Fragment")
//you would bind some control to the model binding in here. For example:
//textfield(model.someBinding)
}
init {
itemProperty.value = model.item
model.bindTo(this)
}
}
class TopLevelController : Controller() {
val myObject1 = MyObject()
val myObject2 = MyObject()
val myObject3 = MyObject()
}
class TopLevelView : View() {
val controller: TopLevelController by inject()
override val root = vbox {
add(setUpObjectFragment(controller.myObject1))
add(setUpObjectFragment(controller.myObject2))
add(setUpObjectFragment(controller.myObject3))
}
fun setUpObjectFragment(obj: MyObject) = find<MyObjectFragment>(Scope(MyObjectModel(obj)))
}
It also seems you're new and are missing a lot of key concepts to utilize from TornadoFX. Using find for instance, is really important for Fragments and Views so they have the proper life cycle.
Then there's Scopes which help with being able to call certain Components with injection.
And finally, there are Model classes, most importantly ItemViewModel which gives you the most functionality with editing, like being able to rollback and commit changes as well as to mark properties as required and add validate filters.
If this isn't a satisfactory solution, please give us more information on what you want, as I might be able to provide a more elegant and concise solution. If these concepts are confusing, please look at Edvin's guide.
I use this code in my application and I find it very ugly.
Is there a smart way of doing this?
for (final ApplicationCategories applicationCategorie : applicationCategories) {
if (applicationCategorie == ApplicationCategories.PROJECTS) {
// invoke right method
} else if (applicationCategorie == ApplicationCategories.CALENDAR) {
// ...
} else if (applicationCategorie == ApplicationCategories.COMMUNICATION) {
} else if (applicationCategorie == ApplicationCategories.CONTACTS) {
} else if (applicationCategorie == ApplicationCategories.DOCUMENTS) {
} else if (applicationCategorie == ApplicationCategories.WORKINGBOOK) {
}
}
My aim is to handle all application categorie enums which contained into the enum list.
The least you can do is to declare the method that handles the behaviour dependent to the enum inside ApplicationCategories. In this way, if you will add a new value to the enum, you will only to change the code relative to enum.
In this way, your code adheres to the Open Closed Principle, and so it is easier to maintain.
enum ApplicationCategories {
PROJECTS,
CALENDAR,
// And so on...
WORKINGBOOK;
public static void handle(ApplicationCategories category) {
switch (category) {
case PROJECTS:
// Code to handle projects
break;
case CALENDAR:
// Code to handle calendar
break;
// And so on
}
}
}
This solution is only feasable if you do not need any external information to handle the enum value.
Remember you can also add fields to enum values.
EDIT
You can also implement a Strategy design pattern if you need. First of all, define a strategy interface and some concrete implementations.
interface CategoryStrategy {
void handle(/* Some useful input*/);
}
class ProjectStrategy implements Strategy {
public void handle(/* Some useful input*/) {
// Do something related to projects...
}
}
class CalendarStrategy implements Strategy {
public void handle(/* Some useful input*/) {
// Do something related to calendars...
}
}
//...
Then, you can modify your enum in order to use the above strategy.
enum ApplicationCategories {
PROJECTS(new ProjectStrategy()),
CALENDAR(new CalendarStrategy()),
// And so on...
WORKINGBOOK(new WorkingBookStrategy());
private CategoryStrategy strategy;
ApplicationCategories(CategoryStrategy strategy) {
this.strategy = strategy;
}
public static void handle(ApplicationCategories category) {
category.strategy.handle(/* Some inputs */);
}
}
Clearly, the above code is only a sketch.
The design pattern you need is the Strategy.
Enums and violation of the Open/Closed Principle
The use of enums when you have to perform a different action for each defined value is a bad practice. As the software evolves, it is likely that you have to spread the if chain around different places. If you add a new enum value, you'll have to add a new if for that value in all these places. Since you may not even be able to find all the places where you have to include the new if, that is a source for bugs.
Such approach also violates the Open/Closed Principle (OCP). Just creating a method to handle each enum value doesn't make your code conformant to OCP. It will make the code more organised but doesn't change anything about the "if" issue.
Java 7 solution with Strategy Pattern
Using Java 7 or prior, you can define a ApplicationCategory interface that all categories will implement. This interface will provide a common method that each category will implement to perform the required actions for that category:
public interface ApplicationCategory {
boolean handle();
}
Usually your method should return something. Since I don't know what is your exact goal, I'm making the method to return just a boolean. It would indicate if the category was handled or not, just as an example.
Then you have to define a class implementing such an interface for each category you have. For instance:
public class CalendarCategory implements ApplicationCategory {
boolean handle(){
//the code to handle the Calendar category
return true;
}
}
public class CommunicationCategory implements ApplicationCategory {
boolean handle(){
//the code to handle the Communication category
return true;
}
}
Now you don't need the enum class and the handle method that was inside it needs to be moved elsewhere, that completely depends on your project. That handle method will be changed to:
public static void handle(ApplicationCategory category) {
//Insert here any code that may be executed,
//regardless of what category it is.
category.handle();
}
You don't need an enum anymore because any variable declared as ApplicationCategory just accepts an object that implements such an interface. If you use the enum together with the Strategy implementation, it will be yet required to change the enum class any time you add a new ApplicationCategory implementation, violating the OCP again.
If you use the Strategy pattern, you don't even need the enum anymore in this case.
Java 8 solution with functional programming and Strategy Pattern
You can more easily implement the Strategy pattern using functional programming and lambda expressions, and avoid the proliferation of class just to provide different implementations of a single method (the handle method in this case).
Since the handle method is not receiving any parameter and is retuning something, this description conforms to the Supplier functional interface. An excellent way to identify what kind of functional interface a method you are defining conforms to, it is studying the java.util.function package.
Once the type of functional interface is identified, we can create just a ApplicationCategory class (that in the Java 7 example was an interface) in a functional way, defining the previous handle method as an attribute of the Supplier type. You must define a setter for this handle attribute to enable changing the handle implementation. Defining a method as an attribute, you are enabling such a method implementation to be changed in runtime, providing a different but far simpler, easier and more maintainable implementation of the Strategy pattern.
If you need to use the category name somewhere, for instance to display it in a user interface, you could define an enum inside the ApplicationCategory class. However, there is no direct relation between the enum value and the handle provided. The enum works just as a tag for the category. It is like a "name" attribute in a Person class, that we usually just use to "tag" and print a person.
public class ApplicationCategory {
//insert all categories here
enum Type {CALENDAR, COMMUNNICATION}
/**
* The Supplier object that will handle this category object.
* It will supply (return) a boolean to indicate if the category
* was processed or not.
*/
private Supplier<Boolean> handler;
private Type type;
/**
* A constructor that will receive a Supplier defining how to
* handle the category that is being created.
*/
public ApplicationCategory(Type type, Supplier<Boolean> handler){
Objects.requireNonNull(type);
this.handler = handler;
setType(type);
}
/**
* Handle the category by calling the {#link Supplier#get()} method,
* that in turn returns a boolean.
*/
public boolean handle(){
return supplier.get();
}
public Type getType(){ return type; }
public final void setHandler(Supplier<Boolean> handler){
Objects.requiredNonNull(handler);
this.handler = handler;
}
}
If you give the behaviour that will handle the enum value at the enum constructor call, as suggested by the other answer provided here, then you don't have how to change the behaviour in runtime and it in fact doesn't conform to the Strategy pattern. Unless you really don't need that, you might implement in that way, but remember it violates the OCP.
How to use the Java 8 functional ApplicationCategory class
To instantiate a ApplicationCategory you have to provide the Type (an enum value) and the handler (that is a Supplier and can be given as a lambda expression). See the example below:
import static ApplicationCategory.CALENDAR;
public class Test {
public static void main(String args[]){
new Test();
}
public Test(){
ApplicationCategory cat = new ApplicationCategory(CALENDAR, this::calendarHandler);
System.out.println("Was " + cat + " handled? " + cat.handle());
}
private boolean calendarHandler(){
//the code required to handle the CALENDAR goes here
return true;
}
}
The this::calendarHandler instruction is a method reference to pass a "pointer" to the calendarHandler method. It is not calling the method (you can see that due to the use of :: instead of . and the lack of parenthesis), it is just defining what method has to be in fact called when the handle() method is called, as can be seen in System.out.println("Was " + cat + " handled? " + cat.handle());
By using this approach, it is possible to define different handlers for different instances of the same category or to use the same handler for a subset of categories.
Unlike other languages, Java provides facilities that specifically allow this sort of thing to be done in a safe object-oriented way.
Declare an abstract method on the enum, and then specific implementations for each enum constant. The compiler will then ensure that every constant has an implementation and nobody has to worry about missing a case somewhere as new values are added:
enum ApplicationCategories {
PROJECTS {
void handle() {
...
}
},
...
public abstract void handle();
}
Then, instead of calling some static handle(category), you just call category.handle()
I have classes with methods with the same names that do the same thing yet they are implemented differently.
Ex:
class converterA {
map(Item1 item1) {
// Implementation details.
}
convert(Item1 item1) {
// Implementation details.
}
translate(Item1 item1) {
// Implementation details.
}
}
class converterB {
map(Item2 item2) {
// Implementation details.
}
convert(Item2 item2) {
// Implementation details.
}
translate(Item2 item2) {
// Implementation details.
}
}
I considered using an interface but the issue is that is that the methods take in different parameters. Yet a template doesn't exactly fit either because Item1 and Item2 operate in different ways. In other words, they don't have common methods so a template doesn't exactly fit either.
Is there a solution here for refactoring the code?
Given your comment "way to... have an interface styled class that can be extended", you might be interested in using templates to express the common "interface":
template <typename Item>
struct Converter
{
virtual void map(Item) = 0;
virtual void convert(Item) = 0;
virtual void translate(Item) = 0;
};
class converterA : public Converter<Item1> {
void map(Item1 item1) final { ... }
void convert(Item1 item) final { ... }
void translate(Item1 item) final { ... }
};
class converterB : public Converter<Item2> {
...same kind of thing...
};
All it buys you though is an expression of the "Converter" interface they share, some compile-time enforcement that the function signatures and names match that (e.g. if you change Converter<> you'll be reminded to update all the derived types), and the ability to handle the derived classes using pointer/references to the template instantiations they derive from (which is not of any ostensible use to you).
I was thinking about using template specialization, but if they both use totally different methods it's not really worth it, although it would be more readable.
I am not sure if this situation would more be related to generics than DTOs, but here it goes:
I have a DTO that represents a Person. A Person can have as children other Person(s) or just ResourceLink to those Person(s). This means that the child can be of either of the 2 types: Person (the DTO) or the ResourceLink. What type it would be, is determined through a queryParam and consequently logically through the flow follwed. I want to represent them using just ONE collection object and am not aware of the best way to do so.
Here is what I have so far:
public class PersonDTO<T> {
#XmlElementWrapper(name = "children")
#XmlElement(name = "child")
List<T> children;
// other stuff
}
With this approach, I need to define the translated type based on an if...else condition.
Earlier I had 2 different collections, one of which remained NULL. I also thought of extracting the relationship thing out in a new DTO as ChildrenDTO (not sure if that's a great idea)
I would like to know if there is a best practice for this situation, otherwise, if it is possible to declare a PersonDTO<PersonDTO> or PersonDTO<ResourceLink> depending on a condition.
Thanks in advance!
I'd suggest instead, using a third type for the elements of List children:
public interface PersonResolver () {
Person resolvePerson ();
}
public class Person implements PersonResolver {
Person resolvePerson () { return this; }
}
public class ResourceLink implements PersonResolver {
Person resolvePerson () {
if (myLinkTargetType == TARGET_TYPE_PERSON)
{ return (Person) myTarget; }
return null;
}
}
The classical strongly typed MVP pattern looks like this in Scala:
trait IView { }
trait Presenter[View <: IView] { // or have it as an abstract type member
val view : View
}
case class View1(...) extends IView { ... }
case object Presenter1 extends Presenter[View1] {
val view = View1(...)
}
Now, I wonder if there is any nice way to improve on it which I am missing...
Nice thing about MVP pattern is that it makes your UI code unit testable.
I'd suggest you to avoid instantiating view in presenter and pass it to constructor.
That will allow you to just mock out the View and unit test the Presenter.
Replace you code
case object Presenter1 extends Presenter[View1] {
val view = View1(...)
}
with
case object Presenter1(val view: View1) extends Presenter[View1] {
...
}