Want to get a message when field value is changed

Discussion in 'Java' started by dlwnsdud1205@gmail.com, Jan 4, 2007.

  1. Guest

    class A{
    private String feeling = ":-(";
    public void smile(){
    str = ":)";
    }
    }
    class B{
    public static void main(){
    A a = new A();
    a.smile(); // the value is changed
    }
    }

    Not modifying class A, I want to get a message when 'feeling' is
    changed.

    Does it require JNI?

    Thanks
     
    , Jan 4, 2007
    #1
    1. Advertising

  2. wrote:
    > class A{
    > private String feeling = ":-(";
    > public void smile(){
    > str = ":)";


    I assume this should have been feeling.

    > }
    > }
    > class B{
    > public static void main(){
    > A a = new A();
    > a.smile(); // the value is changed
    > }
    > }
    >
    > Not modifying class A, I want to get a message when 'feeling' is
    > changed.
    >
    > Does it require JNI?


    I don't think JNI can do it.

    I you can modify class B then you can create a class
    tha extends class A and do the notification in an
    overriden smile method.

    If modifying source code is banned, but modifying
    byte code is OK, then you could look at AOP and AspectJ.

    Arne
     
    =?EUC-KR?B?QXJuZSBWYWpoqapq?=, Jan 4, 2007
    #2
    1. Advertising

  3. wrote:
    > class A{
    > private String feeling = ":-(";
    > public void smile(){
    > str = ":)";
    > }
    > }
    > class B{
    > public static void main(){
    > A a = new A();
    > a.smile(); // the value is changed
    > }
    > }
    >
    > Not modifying class A, I want to get a message when 'feeling' is
    > changed.
    >
    > Does it require JNI?
    >
    > Thanks
    >


    What you want is probably the observer pattern:

    public interface Observer<T> {
    public void notice (T object);
    }

    public final class Observable<T> {
    private T object;
    private Set<Observer<? super T>> observers;
    public Observable (T object) {
    this.object = object;
    observers = new HashSet<Observer<? super T>>;
    }
    public T get () { return object; }
    public void set (T object) {
    this.object = object;
    for (Observer<? super T> observer : observers)
    observer.notice(object);
    }
    public void addObserver (Observer<? super T> observer) {
    observers.add(observer);
    }
    public void removeObserver (Observer<? super T> observer) {
    observers.remove(observer);
    }
    }

    class A {
    private Observable<String> feeling =
    new Observable<String>(":-(");
    public void smile () {
    feeling.set(":)");
    }
    public void addFeelingObserver
    (Observer<? super String> observer) {
    feeling.addObserver(observer);
    }
    public void removeFeelingObserver
    (Observer<? super String> observer) {
    feeling.removeObserver(observer);
    }
    public String getCurrentFeeling () {
    return feeling.get();
    }
    }

    public class StdoutObserver implements Observer<Object> {
    public void notice (Object object) {
    System.out.println("Changed to " + object);
    }
    }

    class B {
    public static void main (String[] args) {
    A a = new A();
    A.addFeelingObserver(new StdoutObserver());
    A.smile(); // Prints "Changed to :)"
    }
    }


    The beauty of this is that you can extend this easily. If something else
    wants notification of feeling changing it can call an A's
    addFeelingObserver as well, and nothing else needs to be changed (in A
    or B or anywhere else). You can add new methods in A that change the
    feeling using feeling.set(whatever) and the observers are automatically
    notified without your having to remember to put a bunch of notifying
    calls in the new method; the need to notify is encapsulated in the
    Observable.set method, and because there's no other way to change the
    field, you can't forget even to do that. The getCurrentFeeling method in
    A demonstrates that A can access and use the field's value as needed.

    And you can observe if any field changes by making it an Observable<Foo>
    instead of a Foo and putting (at least) an addFooObserver method that
    takes an Observer<? super Foo>.

    You can even make A itself observable and make changing feeling notify
    A's observers: make A's constructor private, provide a static factory
    method A.getInstance such as

    public static Observable<A> getInstance () {
    final A a = new A();
    Observable<A> result = new Observable<A>(a);
    a.observer = result;
    a.addFeelingObserver(new Observer<String>() {
    public void notify (String s) {
    a.observer.set(a);
    }
    }
    return result;
    }

    A now needs a private "observer" field of type Observer<A> and that's
    it! This uses an anonymous inner class to observe A's feeling, which
    references the "a" local variable in the getInstance method. "a" has to
    be final for this to work, but that's no problem. It gets bound to the
    same instance of A whose feeling the instance of the anonymous inner
    class is observing, and a new one gets bound to a new instance of that
    observer each time the method runs. The observer notices the string
    change and just changes the Observable<A> the factory method returned to
    refer to the same A it already did refer to. This doesn't change
    anything, except that the set method notifies anything the factory
    method's caller set to observing A. If A's own observers check
    getCurrentFeeling() they will discover that it has been altered.

    The caveat is that if you create a separate Observable<A> wrapping the A
    (e.g. new Observable<A>(A.getInstance().get())) that one will not be
    notified if the feeling changes. Only the one Observable<A> directly
    returned by getInstance will.
     
    John Ersatznom, Jan 4, 2007
    #3
  4. Ian Wilson Guest

    John Ersatznom wrote:
    > wrote:
    >
    >> class A{
    >> private String feeling = ":-(";
    >> public void smile(){
    >> str = ":)";
    >> }
    >> }
    >> class B{
    >> public static void main(){
    >> A a = new A();
    >> a.smile(); // the value is changed
    >> }
    >> }
    >>
    >> Not modifying class A, I want to get a message when 'feeling' is
    >> changed.
    >>
    >> Does it require JNI?
    >>

    >
    > What you want is probably the observer pattern:
    >
    > public interface Observer<T> {
    > public void notice (T object);
    > }
    >
    > public final class Observable<T> {
    > private T object;


    <snip>

    You seem to be reinventing java.util.Observer and java.util.Observable.

    What don't you like about them?
     
    Ian Wilson, Jan 4, 2007
    #4
  5. Chris Uppal Guest

    Ian Wilson wrote:

    > You seem to be reinventing java.util.Observer and java.util.Observable.
    >
    > What don't you like about them?


    I don't know about John, but to me they seem pretty pointless.

    There are several things that pre-packaged utility classes /could/ provide:

    Save implementation effort.

    Allow clearer code.

    Pre-package more flexibility than most developers would bother to provide
    upfront.

    Use advanced implementation techniques.

    The java.util.Observe* classes seem to provide none of these. For instance,
    there is little flexibility in the data passed along with the notification
    (exactly one Object reference -- not even generified (though I can live with
    that ;-)). No flexibility in how the list of Observers is maintained (e.g.
    using a weak collections). No flexibility in how Observers are notified (e.g.
    in a separate thread, or within a comprehensive try-catch clause).

    Now not providing those kinds of flexibility might be justified (to avoid
    over-engineering) but in this case what's left is so /very/ simple that it
    provides no significant advantage to use at all. So why bother ?

    -- chris
     
    Chris Uppal, Jan 4, 2007
    #5
  6. John Ersatznom wrote:
    > wrote:
    >> class A{
    >> private String feeling = ":-(";
    >> public void smile(){
    >> str = ":)";
    >> }
    >> }
    >> class B{
    >> public static void main(){
    >> A a = new A();
    >> a.smile(); // the value is changed
    >> }
    >> }
    >>
    >> Not modifying class A, I want to get a message when 'feeling' is
    >> changed.


    > What you want is probably the observer pattern:


    There was that part with:

    #Not modifying class A

    ....

    Arne
     
    =?EUC-KR?B?QXJuZSBWYWpoqapq?=, Jan 5, 2007
    #6
  7. Chris Uppal wrote:
    > The java.util.Observe* classes seem to provide none of these. For instance,
    > there is little flexibility in the data passed along with the notification
    > (exactly one Object reference -- not even generified (though I can live with
    > that ;-)). No flexibility in how the list of Observers is maintained (e.g.
    > using a weak collections). No flexibility in how Observers are notified (e.g.
    > in a separate thread, or within a comprehensive try-catch clause).
    >
    > Now not providing those kinds of flexibility might be justified (to avoid
    > over-engineering) but in this case what's left is so /very/ simple that it
    > provides no significant advantage to use at all. So why bother ?


    Mine, of course, was generified ... and since any code I post here I
    consider PD, you can extend it to suit. :) Adding cross-thread
    notification is simple -- heck you can just extend Observer<T> to chain
    its notify method to another Observer<T> via a thread pool. You can
    always implement your Observable to pass any complex object as the type
    T too, containing whatever data you desire, encapsulated or un-. It's so
    much fun, it's freaky! :)
     
    John Ersatznom, Jan 6, 2007
    #7
  8. Arne Vajh©ªj wrote:
    > There was that part with:
    >
    > #Not modifying class A


    Then you have a problem.
     
    John Ersatznom, Jan 8, 2007
    #8
  9. John Ersatznom wrote:
    > Arne Vajh©ªj wrote:
    >> There was that part with:
    >>
    >> #Not modifying class A

    >
    > Then you have a problem.


    There are certain possibilities within OOP and AOP
    that can solve the problem depending on the specific
    requirements.

    Arne
     
    =?EUC-KR?B?QXJuZSBWYWpoqapq?=, Jan 9, 2007
    #9
  10. Arne Vajh©ªj wrote:
    > John Ersatznom wrote:
    >
    >>Arne Vajh©ªj wrote:
    >>
    >>>There was that part with:
    >>>
    >>>#Not modifying class A

    >>
    >>Then you have a problem.

    >
    > There are certain possibilities within OOP and AOP
    > that can solve the problem depending on the specific
    > requirements.


    Yes. Decorator comes to mind. If you can subclass A or implement an
    interface A implements, thereby making a substitutable type, you can
    wrap A's mutators with ones that notify callbacks or that directly do
    whatever you need doing. Basically, if you control the code that
    directly calls A's methods, or you control A itself, or you can
    substitute a subclass or wrapper type for A, or any combination of
    those, then you can solve this.

    If not, then you have a nontrivial problem. AOP and annotations *may*
    come to the rescue, but you'll need an AOP expert to help you with that. :)
     
    John Ersatznom, Jan 15, 2007
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    1
    Views:
    691
    Rosanne
    Oct 11, 2005
  2. Sound
    Replies:
    2
    Views:
    453
    Randy Webb
    Sep 28, 2006
  3. mxbrunet
    Replies:
    1
    Views:
    218
  4. VUNETdotUS
    Replies:
    25
    Views:
    459
    Thomas 'PointedEars' Lahn
    Nov 10, 2007
  5. jr
    Replies:
    3
    Views:
    426
Loading...

Share This Page