views:

97

answers:

3
package design.pattern.behavioral;

import design.pattern.behavioral.ChainOfResponsibility.*;

public class ChainOfResponsibility {
    public static class Chain {
        private Request[] requests = null;
        private Handler[] handlers = null;
        public Chain(Handler[] handlers, Request[] requests){
            this.handlers = handlers;
            this.requests = requests;
        }

        public void start() {
            for(Request r : requests)
              for (Handler h : handlers)
                    if(h.handle(r)) break;
        }
    }

    public static class Request {
        private int value;

        public Request setValue(int value){
            this.value = value;
            return this;
        }

        public int getValue() {
            return value;
        }
    }

    public static class Handler<T> {
        private Command<T> command = null;
        public Handler(Command<T> command) {
            this.command = command;
        }
        public boolean handle(T request) {
            return command.execute(request);
        }
    }

    public static abstract class Command<T>{
        public abstract Boolean execute(T request);
    }
}

class TestChainOfResponsibility {
     public static void main(String[] args) {
        new TestChainOfResponsibility().test();
    }

    private void test() {
        new Chain(new Handler[]{ // chain of responsibility
                new Handler<Request>(
                        new Command<Request>(){ // command
                            public Boolean execute(Request condition) {
                                boolean result = condition.getValue() >= 600;
                                if (result)  System.out.println("You are rich: " + condition.getValue()  + " (id: " + condition.hashCode() + ")");
                                return result;
                            }
                        }
                ),
                new Handler<Request>(
                        new Command<Request>(){
                            public Boolean execute(Request condition) {
                                boolean result = condition.getValue() >= 100;
                                if(result) System.out.println("You are poor: " + condition.getValue()  + " (id: " + condition.hashCode() + ")");
                                return result;
                            }
                        }
                ),
        },
        new Request[]{
                new Request().setValue(600), // chaining method
                new Request().setValue(100),
        }
        ).start();
    }
}
+4  A: 

I don't think there is a meaningful answer to such a general question. Design patterns don't exist in isolation and don't have a "perfect form": they live in a context.

A pattern is a solution to a problem in a context.

So without knowing the context of your solution, there is not much we can say about it. What is the concrete problem you are trying to resolve with it? What forces are in play? What are your constraints? Do you have any problems / issues with the current solution? If you give more details about these, maybe we can give a better answer.

Péter Török
This is very clever what you sad, now I realised that - context/background it is very important.On the other hand look for example, at using chaining method in this snippet of code:new Request[]{ new Request().setValue(600), // chaining method new Request().setValue(100), }for me it is especially beautifull that setValue() return reference to Request object, making code shorter and easier.What could you change in this snippet to make this code, cleaner, beauty, shorter.Thank You!
Maciek Kreft
@Maciek, yes, method chaining is a nice idiom indeed, which can make the code more concise. It is often used, e.g. in Hibernate. I think you are using it well here.
Péter Török
Here is also used Command pattern, which great IMHO. Maybe somenthing else we can improve ?
Maciek Kreft
@Maciek, honestly, what you seem to be doing here is polishing code for your own fun. For meaningful "improvement", you need to define criteria by which to judge whether a specific change makes the code better or worse. What are your criteria? Readability? Conciseness? Speed? Number of patterns per line of code? ;-) Patterns are not an asset by themselves - only as far as they actually help you solve real world problems.
Péter Török
+2  A: 

Lambda isn't very descriptive (to most developers). Is it something you are pulling in from functional language theory?

Justin
+1 I agree. Selecting meaningful and good names is a very important part of writing clean, readable code.
Péter Török
Python supports the creation of anonymous functions (i.e. functions that are not bound to a name) at runtime, using a construct called "lambda". This is not exactly the same as lambda in functional programming languages, but it is a very powerful concept that's well integrated into Python and is often used in conjunction with typical functional concepts like filter(), map() and reduce().link:[www.secnetix.de/olli/Python/lambda_functions.hawk] I renamed Lambda to Command, and also removed more than 20 lines of code making this more readable, and less error prone.
Maciek Kreft
A: 

I'd probably just get rid of the 'controlling' class, and wire the individual handlers up to each other directly - use more of an IoC approach, basically.

Example (in C#, forgive me) per request...

    public interface IIntMessage
    {
        void HandleMesasge(int i);
    }

    public class EvenPrinter : IIntMessage
    {
        private IIntMessage m_next;

        public EvenPrinter(IIntMessage next)
        {
            m_next = next;
        }
        public void HandleMesasge(int i)
        {
            if(i % 2 == 0)
            {
                System.Console.WriteLine("Even!");
            }
            else
            {
                m_next.HandleMesasge(i);
            }
        }            
    }
    public class OddPrinter : IIntMessage
    {
        private IIntMessage m_next;

        public OddPrinter(IIntMessage next)
        {
            m_next = next;
        }
        public void HandleMesasge(int i)
        {
            if(i%2 == 1)
            {
                System.Console.WriteLine("Odd!");
            }
            else
            {
                m_next.HandleMesasge(i);
            }
        }
    }

Note that we get rid of the "controlling" class altogether, and simply allow the request handlers to directly chain to each other, without having to go through an intermediary.

Also, I could probably extract out a 'base' chain-of-command request handler, removing some of the duplicate code.

kyoryu
Could you show us changes in source code, to let us know what you mean. Thank you!
Maciek Kreft
... okay, added a sample.
kyoryu