I have an situation when i have an Observer to be a also a subject.
So let's image with have two entites A and B.
When Changes occurs in A's Model other entites should know including B (C,D...Etc).
When Changes occurs in B's Model other entites should know including A (C,D...Etc).
By implmenting the Observer pattern in this way i get an infinite loop betteween A and B.
Is the observer pattren not implmented correctly or do i need another pattren to handle this kind of design ?
Any way her my implementation
public interface ISubject {
public void registreObserver(IObserver obs);
public void removeObserver(IObserver obs);
public void notifyObservers();
}
And the Observer Interface
public interface IObserver {
public void update(ISubject subject);
}
The Model
import java.util.ArrayList;
import java.util.List;
public class AModel implements ISubject {
private List<IObserver> listObservers = new ArrayList<>();
#Override
public void registreObserver(IObserver obs) {
listObservers.add(obs);
}
#Override
public void removeObserver(IObserver obs) {
listObservers.remove(obs);
}
public void loadData(){
notifyObservers();
}
#Override
public void notifyObservers() {
for (IObserver obv : listObservers) {
obv.update(AModel.this);
}
}
}
BModel
import java.util.ArrayList;
import java.util.List;
public class BModel implements ISubject {
private List<IObserver> listObservers = new ArrayList<>();
#Override
public void registreObserver(IObserver obs) {
listObservers.add(obs);
}
#Override
public void removeObserver(IObserver obs) {
listObservers.remove(obs);
}
public void loadData(){
notifyObservers();
}
#Override
public void notifyObservers() {
for (IObserver obv : listObservers) {
obv.update(BModel.this);
}
}
}
The A controller
public class AController implements IObserver {
private AModel model;
public void setModel(AModel model) {
this.model = model;
}
#Override
public void update(ISubject subject) {
System.out.println(" A Changed");
model.loadData();
}
}
The B controller
public class BController implements IObserver {
private BModel model;
public void setModel(BModel model) {
this.model = model;
}
#Override
public void update(ISubject subject) {
System.out.println(" B Changed");
model.loadData();
}
}
Main Program
public class Main {
public static void main(String[] args) {
AModel aModel = new AModel();
AModel bModel = new BModel();
AController aController = new AController();
aController.setModel(aModel);
AController bController = new BController();
bController.setModel(bModel);
aModel.registreObserver(bController);
bModel.registreObserver(aController);
// Here the updates starts a notify b and b notify a and so on
aModel.notifyObservers();
}
}
The reason why you are getting an infinite loop is because each time you update your Observable, you notify its observers, but this notifying process then updates the model again and so it repeats.
Here is an example of how to use the Observer pattern in the way you are looking for:
import java.util.Observable;
import java.util.Observer;
public class Example {
public static void main(String[] args) {
Model modelA = new Model();
Model modelB = new Model();
Observer aController = (observable, arg) -> {
System.out.println("A controller: " + arg);
};
Observer bController = (observable, arg) -> {
System.out.println("B controller: " + arg);
};
modelA.addObserver(bController);
modelB.addObserver(aController);
modelA.update("test");
modelB.update("test2");
}
}
class Model extends Observable {
private String data;
public void update(String data) {
this.data = data;
setChanged();
notifyObservers(data);
}
}
Output:
B controller: test
A controller: test2
Although #arizzle's answer works, I think you are misusing the Observer pattern.
Observer
Define a one-to-many dependency between objects so that when one object changes > state, all its dependents are notified and updated automatically.
Source
Your problem seems more like a many-to-many relationship. In this case, I'd recomend you to use the Mediator Pattern to hide this complexity.
This is the canonic UML Diagram for this pattern:
I'll skip the interface/abstract class definition here to avoid bloating the answer.
Basic implementation:
class Mediator {
private Map<String, Colleague> participants = new HashMap<String, Colleague>();
public void register(Colleague c) {
participants.put(c.getName(), c);
c.setMediator(this);
}
public void send(Colleague from, String message, String to) {
Colleague c = participants.get(to);
if (c != null && c != from) {
c.receive(message, from);
}
}
public void send(Colleague from, String message) {
for (Map.Entry<String, Colleague> e: participants.entrySet()) {}
Colleague c = e.getValue();
if (c != from)) {
c.receive(message, from);
}
}
}
}
abstract class Colleague {
private Mediator mediator;
private String name;
public Colleague(String name) {
this.name = name;
}
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public void send(String msg, String to) {
this.mediator.send(this, msg, to);
}
public void send(String msg) {
this.mediator.send(this, msg);
}
abstract public void receive(String msg, Colleague from);
}
class ConcreteColleague1 {
public void receive(String msg, String from) {
// do something
System.out.println("Received msg: " + msg + " from: " + from.getName());
}
}
class ConcreteColleague2 {
public void receive(String msg, String from) {
// do other thing
System.out.println("Received msg: " + msg + " from: " + from.getName());
}
}
Using it:
Mediator m = new Mediator();
Colleague c1 = new ConcreteColleague1('foo');
Colleague c2 = new ConcreteColleague2('bar');
Colleague c3 = new ConcreteColleague1('baz');
c1.send("test");
c2.send("test");
c3.send("test");
Will print:
"Received msg: test from: foo"
"Received msg: test from: foo"
"Received msg: test from: bar"
"Received msg: test from: bar"
"Received msg: test from: baz"
"Received msg: test from: baz"
This way, when you broadcast a message, you can know for sure that everyone received it, so you don't need to make another broadcast for each colleague to communicate the new state.
Related
I'm using a multiplayer Game Client that's called AppWarp (http://appwarp.shephertz.com), where you can add event listeners to be called back when event's happen, let's assume we'll be talking about the Connection Listener, where you need to implement this interface:
public interface ConnectionRequestListener {
void onConnectDone(ConnectEvent var1);
void onDisconnectDone(ConnectEvent var1);
void onInitUDPDone(byte var1);
}
My goal here is to mainly create a Reactive version of this client to be used in my Apps Internally instead of using the Client itself directly (I'll also rely on interfaces later instead of just depending on the WarpClient itself as in the example, but that's not the important point, please read my question at the very end).
So what I did is as follows:
1) I introduced a new event, named it RxConnectionEvent (Which mainly groups Connection-Related events) as follows:
public class RxConnectionEvent {
// This is the original connection event from the source client
private final ConnectEvent connectEvent;
// this is to identify if it was Connection / Disconnection
private final int eventType;
public RxConnectionEvent(ConnectEvent connectEvent, int eventType) {
this.connectEvent = connectEvent;
this.eventType = eventType;
}
public ConnectEvent getConnectEvent() {
return connectEvent;
}
public int getEventType() {
return eventType;
}
}
2) Created some event types as follows:
public class RxEventType {
// Connection Events
public final static int CONNECTION_CONNECTED = 20;
public final static int CONNECTION_DISCONNECTED = 30;
}
3) Created the following observable which emits my new RxConnectionEvent
import com.shephertz.app42.gaming.multiplayer.client.WarpClient;
import com.shephertz.app42.gaming.multiplayer.client.events.ConnectEvent;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action0;
import rx.subscriptions.Subscriptions;
public class ConnectionObservable extends BaseObservable<RxConnectionEvent> {
private ConnectionRequestListener connectionListener;
// This is going to be called from my ReactiveWarpClient (Factory) Later.
public static Observable<RxConnectionEvent> createConnectionListener(WarpClient warpClient) {
return Observable.create(new ConnectionObservable(warpClient));
}
private ConnectionObservable(WarpClient warpClient) {
super(warpClient);
}
#Override
public void call(final Subscriber<? super RxConnectionEvent> subscriber) {
subscriber.onStart();
connectionListener = new ConnectionRequestListener() {
#Override
public void onConnectDone(ConnectEvent connectEvent) {
super.onConnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_CONNECTED));
}
#Override
public void onDisconnectDone(ConnectEvent connectEvent) {
super.onDisconnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_DISCONNECTED));
}
// not interested in this method (for now)
#Override
public void onInitUDPDone(byte var1) { }
private void callback(RxConnectionEvent rxConnectionEvent)
{
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(rxConnectionEvent);
} else {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
};
warpClient.addConnectionRequestListener(connectionListener);
subscriber.add(Subscriptions.create(new Action0() {
#Override
public void call() {
onUnsubscribed(warpClient);
}
}));
}
#Override
protected void onUnsubscribed(WarpClient warpClient) {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
4) and finally my BaseObservable looks like the following:
public abstract class BaseObservable<T> implements Observable.OnSubscribe<T> {
protected WarpClient warpClient;
protected BaseObservable (WarpClient warpClient)
{
this.warpClient = warpClient;
}
#Override
public abstract void call(Subscriber<? super T> subscriber);
protected abstract void onUnsubscribed(WarpClient warpClient);
}
My question is mainly: is my implementation above correct or should I instead create separate observable for each event, but if so, this client has more than 40-50 events do I have to create separate observable for each event?
I also use the code above as follows (used it in a simple "non-final" integration test):
public void testConnectDisconnect() {
connectionSubscription = reactiveWarpClient.createOnConnectObservable(client)
.subscribe(new Action1<RxConnectionEvent>() {
#Override
public void call(RxConnectionEvent rxEvent) {
assertEquals(WarpResponseResultCode.SUCCESS, rxEvent.getConnectEvent().getResult());
if (rxEvent.getEventType() == RxEventType.CONNECTION_CONNECTED) {
connectionStatus = connectionStatus | 0b0001;
client.disconnect();
} else {
connectionStatus = connectionStatus | 0b0010;
connectionSubscription.unsubscribe();
haltExecution = true;
}
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
fail("Unexpected error: " + throwable.getMessage());
haltExecution = true;
}
});
client.connectWithUserName("test user");
waitForSomeTime();
assertEquals(0b0011, connectionStatus);
assertEquals(true, connectionSubscription.isUnsubscribed());
}
I suggest you avoid extending the BaseObservable directly since it's very error prone. Instead, try using the tools Rx itself gives you to create your observable.
The easiest solution is using a PublishSubject, which is both an Observable and a Subscriber. The listener simply needs to invoke the subject's onNext, and the subject will emit the event. Here's a simplified working example:
public class PublishSubjectWarpperDemo {
public interface ConnectionRequestListener {
void onConnectDone();
void onDisconnectDone();
void onInitUDPDone();
}
public static class RxConnectionEvent {
private int type;
public RxConnectionEvent(int type) {
this.type = type;
}
public int getType() {
return type;
}
public String toString() {
return "Event of Type " + type;
}
}
public static class SimpleCallbackWrapper {
private final PublishSubject<RxConnectionEvent> subject = PublishSubject.create();
public ConnectionRequestListener getListener() {
return new ConnectionRequestListener() {
#Override
public void onConnectDone() {
subject.onNext(new RxConnectionEvent(1));
}
#Override
public void onDisconnectDone() {
subject.onNext(new RxConnectionEvent(2));
}
#Override
public void onInitUDPDone() {
subject.onNext(new RxConnectionEvent(3));
}
};
}
public Observable<RxConnectionEvent> getObservable() {
return subject;
}
}
public static void main(String[] args) throws IOException {
SimpleCallbackWrapper myWrapper = new SimpleCallbackWrapper();
ConnectionRequestListener listner = myWrapper.getListener();// Get the listener and attach it to the game here.
myWrapper.getObservable().observeOn(Schedulers.newThread()).subscribe(event -> System.out.println(event));
listner.onConnectDone(); // Call the listener a few times, the observable should print the event
listner.onDisconnectDone();
listner.onInitUDPDone();
System.in.read(); // Wait for enter
}
}
A more complex solution would be to use one of the onSubscribe implementations to create an observable using Observable.create(). For example AsyncOnSubscibe. This solution has the benefit of handling backperssure properly, so your event subscriber doesn't become overwhelmed with events. But in your case, that sounds like an unlikely scenario, so the added complexity is probably not worth it.
I have recently started learning OSGi. While experimenting with Apache Aries and OSGi blueprint, I created the following set-up:
Bundle A :
public interface IMessageSender {
String send(String message);
String getServiceName();
}
public interface IMessageSenderFactory {
String name();
IMessageSender create();
}
Bundle B (SMSSenderFactory is exported as a service):
public class SMSSender implements IMessageSender {
public String send(String message) {
return "Sent by SMS : "+message;
}
public String getServiceName() {
return "SMS";
}
}
public class SMSSenderFactory implements IMessageSenderFactory {
public String name() {
return "SMS";
}
public IMessageSender create() {
return new SMSSender();
}
}
Bundle C :
public class BundleManagerImpl implements BundleManager{
BundleContext bundleContext;
Map<IMessageSenderFactory, List<ServiceRegistration>> senders = new HashMap<IMessageSenderFactory, List<ServiceRegistration>>();
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
//reference listener method
public void addSenderFactory(IMessageSenderFactory senderFactory) {
this.senders.put(senderFactory, new ArrayList<ServiceRegistration>());
}
//reference listener method
public void removeSenderFactory(IMessageSenderFactory senderFactory){
List<ServiceRegistration> registeredSenders = this.senders.get(senderFactory);
if (registeredSenders != null){
for (ServiceRegistration serviceRegistration : registeredSenders) {
serviceRegistration.unregister();
}
}
this.senders.remove(senderFactory);
}
#Override
public List<String> listFactories(){
List<String> list = new ArrayList<String>();
for (IMessageSenderFactory senderFactory : senders.keySet()) {
list.add(senderFactory.name());
}
return list;
}
#Override
public void createSenderServiceInstance(String type){
IMessageSender sender = null;
for (IMessageSenderFactory senderFactory : senders.keySet()) {
if (senderFactory.name().equals(type)){
sender = senderFactory.create();
ServiceRegistration registration = bundleContext.registerService(IMessageSender.class.getName(), sender, null);
this.senders.get(senderFactory).add(registration);
}
}
}
}
Bundle D:
public class MessageServiceImpl implements MessageService {
List<IMessageSender> senders = new ArrayList<IMessageSender>();
//reference listener method
public void addSender(IMessageSender sender) {
this.senders.add(sender);
}
//reference listener method
public void removeSender(IMessageSender sender){
this.senders.remove(sender);
}
public List<String> send(String message) {
List<String> list = new ArrayList<String>();
for (IMessageSender sender : this.senders) {
String response = sender.send(message);
list.add(MessageFormat.format("Sent by : {0}; Response : {1}", sender.getServiceName(), response));
}
return list;
}
}
The goal was to allow creation of multiple, variable number of instances of the SMSSender service.
So my questions are:
1 - Is there anything wrong with this approach? I am creating an SMSSender instance, in bundle B and registering it as a service in Bundle C. Would this lead to any issues or does it violate any rule of OSGi?
2 - Are there any other approaches to reaching the same goal?
EDIT:
Bundle E (added later, exports EmailSenderFactory as service)
public class EmailSender implements IMessageSender {
public String send(String message) {
return "Sent by Email : "+message;
}
public String getServiceName() {
return "Email";
}
}
public class EmailSenderFactory implements IMessageSenderFactory {
public String name() {
return "Email";
}
public IMessageSender create() {
return new EmailSender();
}
}
I'm stuck on this assignment. I'm given an abstract Observer class with only 1 constructor in it, a constructor with parameters/arguments. (refer below)
public static void main(String[] args) {
PairOfNumbers numbers1 = new PairOfNumbers();
PairOfNumbers numbers2 = new PairOfNumbers();
SumObserver sum = new SumObserver(numbers1);
ProductObserver prod = new ProductObserver(numbers2);
MultiSubjectObserver m = new MultiSubjectObserver();
m.addSubject(numbers1);
m.addSubject(numbers2);
numbers1.setNumbers(20, 10);
numbers2.setNumbers(-10, 15);
}
class Subject {
private List<Observer> observers=new ArrayList<Observer>();
public void attachObserver(Observer observer) {
this.observers.add(observer);
}
public void detachObserver(Observer observer) {
this.observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer: this.observers)
observer.update(this);
}
}
class PairOfNumbers extends Subject {
private double number1, number2;
public double getNumber1() { return this.number1; }
public double getNumber2() { return this.number2; }
public void setNumbers(double d1, double d2) {
this.number1=d1; this.number2=d2;
this.notifyObservers(); // don't forget to do this!
}
}
abstract class Observer {
public Observer(Subject subject) {
subject.attachObserver(this);
}
abstract public void update(Subject subject);
}
class SumObserver extends Observer {
public SumObserver(PairOfNumbers pair) {
super(pair);
}
public void update(Subject subject) {
PairOfNumbers numbers=(PairOfNumbers)subject;
System.out.println("New sum is: "+(numbers.getNumber1()+numbers.getNumber2()));
}
}
class ProductObserver extends Observer {
public ProductObserver(PairOfNumbers pair) {
super(pair);
}
public void update(Subject subject) {
PairOfNumbers numbers=(PairOfNumbers)subject;
System.out.println("New product is: "+(numbers.getNumber1()*numbers.getNumber2()));
}
}
Okay, now I'm suppose to create another class which inherits from the above class.
class MultiSubjectObserver extends Observer{
public MultiSubjectObserver(PairOfNumbers pair){
super(pair);
}
public void addSubject(PairOfNumbers pair){
pair.attachObserver(this);
}
public void update(Subject subject){
PairOfNumbers numbers=(PairOfNumbers)subject;
System.out.println("MultiSubjectObserver activated with numbers: " + (numbers.getNumber1())+", "+(numbers.getNumber2()));
}
}
Is there a way to create a constructor inside the MSO Class which requires no parameter/argument? For example
public MultiSubjectObserver(){
//enter code here
}
Please guide me on this one. Had been thinking for days. Thanks in advance! :D
The instruction is to: Modify the source code to handle any number of Subject objects per Observer.
Expected output:
New sum is: 30.0
MultiSubjectObserver activated with numbers: 20.0, 10.0
New product is: -150.0
MultiSubjectObserver activated with numbers: -10.0, 15.0
Yes you can do this, create a no-arg child class, but you still must call the arg-needing super constructor within the child constructor.
This:
class Child extends Super {
public Child() {
super(args_are_needed);
}
}
The tricky part would be -- what to pass into the super constructor in this default case? In your case this could be:
public MultiSubjectObserver(){
super(null);
}
Caveat: and this will lead to a NullPointerException when the super's constructor is called, due to the line, subject.attachObserver(this);, so no, you can't do this.
A better solution: make sure that MultiSubjectObserver does not extend from Observer!
Perhaps something like:
class MultiSubjectObserver {
private List<Observer> observerList = new ArrayList<Observer>();
public void addSubject(PairOfNumbers numbers1) {
observerList.add(new InnerObserver(numbers1));
}
private class InnerObserver extends Observer {
public InnerObserver(Subject subject) {
super(subject);
}
#Override
public void update(Subject subject) {
System.out.println("From multi-observer: " + subject);
}
}
}
But for this to work, you'd have to give PairOfNumbers a decent toString method, perhaps,
#Override
public String toString() {
return String.format("[%.4f, %.4f]", number1, number2);
}
Edit
Based on the output:
class MultiSubjectObserver {
private static final String FORMAT_STRING = "MultiSubjectObserver activated with numbers: %.1f, %.1f%n";
private List<Observer> observerList = new ArrayList<Observer>();
public void addSubject(PairOfNumbers numbers1) {
observerList.add(new InnerObserver(numbers1));
}
private class InnerObserver extends Observer {
public InnerObserver(Subject subject) {
super(subject);
}
#Override
public void update(Subject subject) {
System.out.printf(FORMAT_STRING, ((PairOfNumbers)subject).getNumber1(), ((PairOfNumbers)subject).getNumber1());
}
}
}
Although that casting is a bit skanky. I like the toString() version much better.
So I tried to make a subscription model with generics.. it looked nice, but now I'm running into some issues.
Receiver
public interface Receiver<E> {
public void receive(E event);
}
Subscription registry
public class ClientRegistry<T> {
private Set<Receiver<T>> clients = new HashSet<Receiver<T>>();
public void subscribe(Receiver<T> client) {
clients.add(client);
}
public void unsubscribe(Receiver<T> client) {
clients.remove(client);
}
public void broadcast(T eventObject) {
for(Receiver<T> client: clients) {
client.receive(eventObject);
}
}
}
Sounds good so far, eh?
Now the problems come:
public class Screen implements Receiver<KeyEvent>, Receiver<MouseMoveEvent> {
#Override
public void receive(KeyEvent event)
{
// work
}
#Override
public void receive(MouseMoveEvent event)
{
// work
}
}
Now this is invalid syntax:
The interface Receiver cannot be implemented more than once
with different arguments: Receiver<MouseMoveEvent> and Receiver<KeyEvent>
How can I alter my system to keep it as generic as possible, but make it work?
Don't make the Screen class itself implement the two Receiver interfaces. Instead, use composition:
public class Screen {
private Receiver<KeyEvent> keyReceiver = new Receiver<KeyEvent>() {
...
};
private Receiver<MouseEvent> mouseReceiver = new Receiver<MouseEvent>() {
...
};
}
I would reverse the order, and use a Visitor Pattern:
import java.util.*;
interface Event{
void receive(Receiver receiver);
}
class KeyEvent implements Event{
#Override
public void receive(Receiver receiver){
receiver.receive(this);
}
}
class MouseEvent implements Event {
#Override
public void receive(Receiver receiver){
receiver.receive(this);
}
}
interface Receiver {
void receive(KeyEvent event);
void receive(MouseEvent event);
}
class ClientRegistry {
private Set<Receiver> clients = new HashSet<Receiver>();
public void subscribe(Receiver client) {
clients.add(client);
}
public void unsubscribe(Receiver client) {
clients.remove(client);
}
public void broadcast(Event eventObject) {
for(Receiver client: clients) {
eventObject.receive(client);
}
}
}
public class Screen implements Receiver {
public void receive(KeyEvent event) {
//work
System.out.println("Processing key event");
}
public void receive(MouseEvent event) {
//work
System.out.println("Processing mouse event");
}
public static void main(String[] args){
ClientRegistry registry = new ClientRegistry();
registry.subscribe(new Screen());
registry.broadcast(new MouseEvent());
}
}
There is not way to generify the Receiver interface, but it is indeed type safe and as you can see, I reverse the order, since now it is the event the one which chooses the receiver and not otherwise.
I'm reading "Design Pattern for Dummies". I read and practiced Decorator Pattern. With Decorator Pattern, we can decorate an object with anything. Now, I want to remove decorated object before decorated.I have solved this problem by an ArrayList but I still feel it's not good. Can you tell me how to remove a decorated object? And what is a better way?
this is my way:
Computer.java
public class Computer {
public Computer() {
}
public String description() {
return "computer";
}
}
ComponentDecorator.java
public abstract class ComponentDecorator extends Computer {
#Override
public abstract String description();
}
CD.java
public class CD extends ComponentDecorator {
private Computer computer;
public CD() {
}
public CD(Computer computer) {
this.computer = computer;
}
#Override
public String description() {
return computer.description() + " and a CD";
}
}
Disk.java
public class Disk extends ComponentDecorator {
private Computer computer;
public Disk() {
}
public Disk(Computer c) {
computer = c;
}
#Override
public String description() {
return computer.description() + " and a disk";
}
}
Monitor.java
public class Monitor extends ComponentDecorator {
private Computer computer;
public Monitor() {
}
public Monitor(Computer computer) {
this.computer = computer;
}
#Override
public String description() {
return computer.description() + " and a monitor";
}
}
Main.java
import java.util.ArrayList;
import java.util.Arrays;
public class Main {
static ArrayList<ComponentDecorator> list = new ArrayList<>();
public static void main(String[] args) {
addComponent(new CD(), new Disk(), new Monitor());
System.out.println(list.size());
Computer penIII = getComputer();
removeComponent(new Monitor());
penIII = getComputer();
System.out.println(penIII.description());
}
private static void addComponent(ComponentDecorator... comp) {
list.addAll(Arrays.asList(comp));
}
private static void removeComponent(ComponentDecorator comp) {
for(ComponentDecorator c : list) {
if(c.getClass() == comp.getClass()) {
list.remove(list.indexOf(c));
break;
}
}
}
private static Computer getComputer() {
Computer c = new Computer();
Class e;
for(ComponentDecorator d : list) {
e = d.getClass();
try {
c = (Computer) e.getConstructor(new Class[]{Computer.class}).newInstance(c);
} catch(Exception ex) {
ex.printStackTrace();
}
}
return c;
}
}
A nicer way would be adding the "removeDecorator" method to your ComponentDecorator class.
public abstract class ComponentDecorator {
private ComponentDecorator subject;
public ComponentDecorator(ComponentDecorator subject) {
this.subject = subject;
}
#Override
public abstract String description();
}
public void removeDecorator(ComponentDecorator toRemove) {
if (subject == null) {
return;
} else if (subject.equals(toRemove)) {
subject = subject.getSubject();
} else {
subject.removeDecorator(toRemove);
}
}
public ComponentDecorator getSubject() {
return subject;
}
// Computer
public class Computer extends ComponentDecorator{
public Computer() {
super(null);
}
public String description() {
return "computer";
}
// CD
public class CD extends ComponentDecorator {
public CD(ComponentDecorator computer) {
super(computer);
}
#Override
public String description() {
return getSubject().description() + " and a CD";
}
}
// main
public static void main(String[] args) {
ComponentDecorator penIII = new Computer();
penIII = new CD(penIII);
penIII = new Monitor(penIII);
System.out.println(penIII.description());
}
}
If you don't have the reference of the decorator to remove, you can create another method that the a Class instead.
You'll need to the decorated object as "ComponentDecorator" instead of "Computer" however. I suggest to make the Computer class extends ComponentDecorator instead of the other way around.
I suspect I'm misunderstanding your question, but to get the decorated (inner) object out of the decorator, you can just add a get method to the decorators. Add
public abstract Computer getDecorated();
to ComponentDecorator and
public Computer getDecorated(){return computer;}
to each subclass (CD, Monitor, ...). Is that what you were looking for?
Add two methods to an interface, undecorate() and removeDecoration(String className):
ThingInterface.java
public interface ThingInterface {
public ThingInterface undecorate();
public ThingInterface removeDecoration(String className);
public String nonDecoratedString();
public String decoratedString();
}
Your base class will simply return itself for those methods:
BaseThing.java
public class BaseThing implements ThingInterface {
private String basicString;
public BaseThing(String string) {
basicString = string;
}
#Override
public ThingInterface undecorate() {
return this;
}
#Override
public ThingInterface removeDecoration(String className) {
return this;
}
#Override
public String nonDecoratedString() {
return basicString;
}
#Override
public String decoratedString() {
return basicString;
}
}
Now the real meat of what you need is in the abstract class:
AbstractThingDecorator.java
public abstract class AbstractThingDecorator implements ThingInterface {
private ThingInterface thing;
public AbstractThingDecorator(ThingInterface thing) {
this.thing = thing;
}
#Override
public ThingInterface removeDecoration(String className) {
ThingInterface undecorate = this;
if(this.getClass().getName() == className) {
undecorate = this.undecorate();
}
else {
ArrayList<String> classStack = new ArrayList();
while(undecorate != undecorate.undecorate()) {
if(undecorate.getClass().getName() != className) {
classStack.add(undecorate.getClass().getName());
}
undecorate = undecorate.undecorate();
}
for(int i = classStack.size()-1;i == 0;i--) {
try {
Class<?> clazz = Class.forName(classStack.get(i));
Constructor<?> ctor = clazz.getConstructor(ThingInterface.class);
Object object = ctor.newInstance(new Object[] { undecorate });
undecorate = (ThingInterface) object;
}
catch(Exception e) {
System.out.println("Exception:" + e.getMessage());
}
}
}
return undecorate;
}
#Override
public ThingInterface undecorate() {
return this.thing;
}
#Override
public String nonDecoratedString() {
return thing.nonDecoratedString();
}
#Override
public String decoratedString() {
return thing.decoratedString();
}
}
I'm adding two simple decorators, ThingDecorator and FancyThingDecorator:
ThingDecorator.java
public class ThingDecorator extends AbstractThingDecorator {
public ThingDecorator(ThingInterface thing) {
super(thing);
}
#Override
public ThingInterface undecorate() {
return super.undecorate();
}
#Override
public String decoratedString() {
return super.decoratedString() + ", decorated";
}
}
FancyThingDecorator.java
public class FancyThingDecorator extends AbstractThingDecorator {
public FancyThingDecorator(ThingInterface thing) {
super(thing);
}
#Override
public ThingInterface undecorate() {
return super.undecorate();
}
#Override
public String decoratedString() {
return super.decoratedString() + ", fancy";
}
}
Finally, my java main:
Decorator.java
public class Decorator {
/**
* #param args
*/
public static void main(String[] args) {
ThingInterface thing = new BaseThing("Basic string");
ThingInterface decorator = new ThingDecorator(thing);
ThingInterface fancyDecorator = new FancyThingDecorator(thing);
ThingInterface extraFancy = new FancyThingDecorator(new ThingDecorator(thing));
ThingInterface undecorate = new FancyThingDecorator(new ThingDecorator(thing));
System.out.println("Basic thing is: " + thing.decoratedString()+".");
System.out.println("Decorated thing is: " + decorator.decoratedString()+".");
System.out.println("Fancy thing is: " + fancyDecorator.decoratedString()+".");
System.out.println("Decorated fancy thing is: " + extraFancy.decoratedString()+".");
while(extraFancy.undecorate() != extraFancy) {
extraFancy = extraFancy.undecorate();
System.out.println("Rolling back decorations: " + extraFancy.decoratedString()+".");
}
System.out.println("Decoration chain before removal is: " + undecorate.decoratedString());
System.out.println("Removing decoration for " + ThingDecorator.class.getName());
undecorate = undecorate.removeDecoration(ThingDecorator.class.getName());
System.out.println("Decoration chain after removal is: " + undecorate.decoratedString()+".");
}
}
The output is:
Basic thing is: Basic string.
Decorated thing is: Basic string, decorated.
Fancy thing is: Basic string, fancy.
Decorated fancy thing is: Basic string, decorated, fancy.
Rolling back decorations: Basic string, decorated.
Rolling back decorations: Basic string.
Decoration chain before removal is: Basic string, decorated, fancy
Removing decoration for ThingDecorator
Decoration chain after removal is: Basic string, fancy.