java – List with object and index filtering out the object depends upon the index present at list

I have a following list which indicates the indexes.

 List<Integer> integerList = Arrays.asList(1, 3, 5, 6); // index

I have the following collection of objects.

Collection<Test> testCollection = new ArrayList<>();

Test test01 = new Test(0, "A"); // 0
Test test02 = new Test(1, "B"); // 1
Test test03 = new Test(2, "C"); // 2
Test test04 = new Test(3, "D"); // 3
Test test05 = new Test(4, "E"); // 4
Test test06 = new Test(5, "F"); // 5

testCollection.add(test01);
testCollection.add(test02);
testCollection.add(test03);
testCollection.add(test04);
testCollection.add(test05);
testCollection.add(test06);

The integerList has indexes which are present on testCollection. I want to filter out the testCollection which will have object consisting the index 1, 3, 5. Index 6 is not present on object collection.

I wrote the code as below example. Is there any better as like Java 8 way?

List<Test> testList = new ArrayList<>(testCollection);
List<Test> newTestList = new ArrayList<>();

for (Integer integer : integerList) {

  for (int j = 0; j < testList.size(); j++) {

    if (integer == j) {
      newTestList.add(testList.get(j));
    }
  }
}
System.out.println(newTestList);

It will have the following output as result:

(Test{id=1, name='B'}, Test{id=3, name='D'}, Test{id=5, name='F'})

The class Test has following information.

class Test {
  private int id;
  private String name;
}

object oriented – sharing and decoupling data

I basically want to know how you would review this code and design.

Right now, there seems to be a tight coupling so I feel like I’ve violated some rules about data access and responsibility. Seems like there may be some

code smells

  • Config is shared by all tasks, allowing some tasks access to irrelevant services and data.
  • StatusObj used to save and share data throughout workflow. It also has state which should be contained in stateMachine.
  • Current task isnt defined any place. statusObj.task is only updated after success. Doesn’t seem right.
  • Starting whole worfklow inside of a block?
  • Also realizing the input of nextTask is emitted from publisher, but could also be accessed from self.config.statusObj.task. so I implement this stream to retrieve updated statusObj, but its not even necessary?

Also how this design could be extended handle interruptions, resume, cancel. What kind of general edge cases should I be thinking about.

Definitions:

  • TaskService – Initiates & manages workflow, and encapsulates required dependencies/services

  • Task – an async executable task.

  • StateMachine – manages state, provides next task in workflow
  • Publisher – Drives workflow by emitting completed tasks via StatusObj.task
  • StatusObj – Represents status of workflow. is updated by a task when data is fetched and task completes. Is also persisted in db.
  • TaskResponseHandler – Handles success, error, and completion of publisher stream. On success, it saves statusObj to db and publishes, so next task can take place.
  • Config– contains services, api’s, helpers needed for task to execute. So Config also contains the statusObj which contains value retrieved from last task.

Worflow:

I’ve defined a persist-able object statusObj that is updated throughout the workflow.

When a task completes successfully with data, it assigns that data to statusObj and emits to publisher.

responseHandler saves, and emits statusObj. responseHandler would also handle all possible errors related to task failure at this time.

last completed task via statusObj.task is used to map the next task, via stateMachine.

class TaskService {
    var sessionManager: SessionMaanger
    var config: Config
    var stateMachine: StateMachine
    var publisher: PassThroughSubject<Task, Never>
    var responseHandler: Subscriber

    @objc func execute() {
        sessionManager.requestSession(for: self)
        block = { _ in
            // can start workflow now.
            self.subscribe()
            self.publisher.send(self.config.statusObj!) // send initial statusObj.
        }
    }

    @objc func subscribe() {
        publisher
            .setFailureType(to: MyError.self)
            .map { self.nextTask(context: $0) }
            .flatMap { $0!.execute() }
            .subscribe(handler)
    }

    private func nextTask(_ code: TaskCode) -> Task? {
        // state machine has internal state thats not persisted right now but needs to.
        // has a table to output next task, given the internal state, and last completed task.
        switch (stateMachine.nextTask(task)) {
        case .A:
            return TaskA(self.config)
        case .B:
            return TaskB(self.config)
        default: return nil
        }
    }

    func resume() {

    }

    func abort() {
    }

}


class ResponseHandler: Subscriber {
    typealias Input = StatusObj?
    typealias Failure = MyError

    // from taskService
    var publisher: PassthroughSubject<StatusObj, Never>

    init(publisher: PassthroughSubject<StatusObj, Never>) {
        self.publisher = publisher
    }

    func receive(subscription: Subscription) {
        subscription.request(.max(3))
    }

    func receive(_ input: StatusObj?) -> Subscribers.Demand {
        input!.save()
        publisher.send(input!) // emit, for next task to execute
        return .unlimited
    }

    func receive(completion: Subscribers.Completion<MyError>) {
        print("stream completed")
        switch (completion) {
        case .failure(let err):
            print("error (err)")
        case .finished:
            //context.save()
            publisher.send(completion: .finished)
        }
    }
}


class TaskA {
    var config: Config
    var publisher: PassthroughSubject<StatusObj, MyError> // local publisher for async workaround

    init(_ config: Config) {
        self.config = config
    }
    func execute() -> PassthroughSubject<StatusObj, MyError> {
        completionBlock { data in
            self.config.statusObj.task = self.task
            self.config.statusObj.payloadFromTaskA = data
            publisher.send(data)
            // if error would handle here also. publisher(send: error)
        }
    }
}


class StatusObj {
    var state: State // stored in `state machine`, but if need to resume, state needs to be saved
    var task: TaskCode // enum of each task/event. 
    var payloadFromTaskA: Data
    var payloadFromTaskB: String
    var payloadFromTaskD: String
    var retryCount: Int
} 

class Config {
    var statusObj: StatusObj
    var serviceForTaskBAPI: API
    var authToken: String
}

In the depth of field, where is the clearest image of the object?

In the depth of field, where is the clearest image of the object? I ’m not asking about image distance. I ’m asking about how far away from the lens the object is when the image is clearest. How to calculate this distance?

Java: Error deserialising an aggregate object from JSON (HAS-A relationship)

I am getting a Can not set com.google.api.services.androidmanagement.v1.model.HardwareInfo field com.google.api.services.androidmanagement.v1.model.Device.hardwareInfo to java.util.LinkedHashMap error when I am converting a Google API Services Device object to JSON (using Jackson 2.10.0) and reading back from it in a test. The Device object consists of objects of HardwareInfo, MemoryInfo objects that seems to be failing since the ObjectMapper is reading them as LinkedHashMap instead of the actual types. I tried searching on StackOverflow and went through a load of articles but none of them seem to be addressing this JsonMappingException.

What am I doing wrong and how do I fix this? I tried using Mixin since this is a Google POJO and I cannot modify properties directly, but wasn’t able to resolve the problem. Any help regarding this would be greatly appreciated! Thanks.

The complete test code is:

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.testng.annotations.Test;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.api.services.androidmanagement.v1.model.Device;
import com.google.api.services.androidmanagement.v1.model.HardwareInfo;
import com.google.api.services.androidmanagement.v1.model.MemoryInfo;
import com.google.api.services.androidmanagement.v1.model.SoftwareInfo;
import com.google.common.collect.ImmutableMap;

/**
 * TODO: Document this class.
 */
public class DeviceTest {


    @Test
    public void myTest() {

        // code to build the test Device object 
        Device device = new Device();
        final List<String> prevNameList = Arrays.asList("prev-1", "prev-2", "prev-3");

        final HardwareInfo hwInfo = new HardwareInfo();
        hwInfo.setBrand("hwinfo-brand");
        hwInfo.setDeviceBasebandVersion("hwinfo-baseband-version");
        hwInfo.setManufacturer("test-manufacturer");
        hwInfo.setModel("hwinfo-model");
        hwInfo.setSerialNumber("hwinfo-serial-no");
        hwInfo.setHardware("hwinfo-hardware");

        final MemoryInfo memoryInfo = new MemoryInfo();
        memoryInfo.setTotalInternalStorage(123456789L);
        memoryInfo.setTotalRam(123456789L);

        final Map<String, String> propsMap = ImmutableMap.of(
                "prop1", "x86",
                "prop2", "ARM",
                "prop3", "Intel Itanium-based");

        device.setPolicyName("test-policy-name");
        device.setAppliedPolicyName("test-applied-policy-name");
        device.setEnrollmentTokenName("test-enrollment-token-name");
        device.setEnrollmentTokenData("test-enrollment-token-data");
        device.setEnrollmentTime("2020-01-01T00:00:00.000Z");
        device.setLastPolicySyncTime("2020-01-01T00:00:00.000Z");
        device.setLastStatusReportTime("2020-01-01T00:00:00.000Z");
        device.setLastPolicyComplianceReportTime("2020-01-01T00:00:00.000Z");
        device.setUserName("test-user-name");
        device.setName("test-name");

        device.setPreviousDeviceNames(prevNameList);
        device.setSystemProperties(propsMap);
        device.setHardwareInfo(hwInfo);
        device.setMemoryInfo(memoryInfo);

        ObjectMapper mapper = buildMapper();
        try {
            // code to convert object to JSON
            final String json = mapper.writeValueAsString(device);
            final String jsonHwInfo = mapper.writeValueAsString(device);
            System.out.println(json);

            // code to read JSON to object
            final Device deserializedDevice = mapper.readValue(json, Device.class);
            System.out.println(deserializedDevice);
        } catch (IOException | JsonProcessingException e) {
            e.print
        }
    }

    private static ObjectMapper buildMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

        return mapper;
    }

}

The output for this test is:

{"appliedPolicyName":"test-applied-policy-name","enrollmentTime":"2020-01-01T00:00:00.000Z","enrollmentTokenData":"test-enrollment-token-data","enrollmentTokenName":"test-enrollment-token-name","hardwareInfo":{"brand":"hwinfo-brand","deviceBasebandVersion":"hwinfo-baseband-version","hardware":"hwinfo-hardware","manufacturer":"test-manufacturer","model":"hwinfo-model","serialNumber":"hwinfo-serial-no"},"lastPolicyComplianceReportTime":"2020-01-01T00:00:00.000Z","lastPolicySyncTime":"2020-01-01T00:00:00.000Z","lastStatusReportTime":"2020-01-01T00:00:00.000Z","memoryInfo":{"totalInternalStorage":123456789,"totalRam":123456789},"name":"test-name","policyName":"test-policy-name","previousDeviceNames":("prev-1","prev-2","prev-3"),"systemProperties":{"prop1":"x86","prop2":"ARM","prop3":"Intel Itanium-based"},"userName":"test-user-name"}
com.fasterxml.jackson.databind.JsonMappingException: Can not set com.google.api.services.androidmanagement.v1.model.HardwareInfo field com.google.api.services.androidmanagement.v1.model.Device.hardwareInfo to java.util.LinkedHashMap (through reference chain: com.google.api.services.androidmanagement.v1.model.Device("hardwareInfo"))
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394)
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:353)
    at com.fasterxml.jackson.databind.deser.std.ContainerDeserializerBase.wrapAndThrow(ContainerDeserializerBase.java:181)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:539)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:364)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:29)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4202)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3205)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3188)
    at com.mobileiron.polaris.service.androidwork.androidmanagementapi.DeviceTest.myTest(DeviceTest.java:89)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:104)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:645)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:851)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1177)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
    at org.testng.TestRunner.privateRun(TestRunner.java:756)
    at org.testng.TestRunner.run(TestRunner.java:610)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:387)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:382)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:340)
    at org.testng.SuiteRunner.run(SuiteRunner.java:289)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1293)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1218)
    at org.testng.TestNG.runSuites(TestNG.java:1133)
    at org.testng.TestNG.run(TestNG.java:1104)
    at com.intellij.rt.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:66)
    at com.intellij.rt.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:110)
Caused by: java.lang.IllegalArgumentException: Can not set com.google.api.services.androidmanagement.v1.model.HardwareInfo field com.google.api.services.androidmanagement.v1.model.Device.hardwareInfo to java.util.LinkedHashMap
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
    at java.lang.reflect.Field.set(Field.java:764)
    at com.google.api.client.util.FieldInfo.setFieldValue(FieldInfo.java:245)
    at com.google.api.client.util.FieldInfo.setValue(FieldInfo.java:206)
    at com.google.api.client.util.GenericData.put(GenericData.java:103)
    at com.google.api.client.util.GenericData.put(GenericData.java:47)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:534)
    ... 30 more

dnd 5e – Is an Echo Knight fighter’s “echo” a tangible object, for the purpose of physical interaction?

The Explorer’s Guide to Wildemount sourcebook contains a new Fighter subclass, the Echo Knight. Echo Knights have the ability to summon an “echo” of themselves; per the overall subclass description (p. 183):

the Echo Knight has mastered the art of using dunamis to summon the fading shades of unrealized timelines to aid them in battle.

The Manifest Echo feature also describes it as follows:

This echo is a magical, translucent, gray image of you (…) It is the same size as you, and it occupies its space.

In this unofficial tweet from March 2020, Jeremy Crawford confirms that an echo is an object.

Is an “echo” a tangible object, for the purpose of being interacted with (e.g. a giant picking it up from the ground like a large bottle of beer)?

Remove object or person from any photo PEFRECTLY for $5

Remove object or person from any photo PEFRECTLY

I will remove an object or a person from any photo, cutout image, and background removal perfectly with high-precision.

My service for this offer includes the following:

• Remove an object from 1 image

• Remove a person from 1 image

• Retouching your image

• 24-hour Express delivery

DISCOUNT:

I will give a 10% discount if there are more than 5 images.

FOR CUSTOM ORDERS
, please contact me and I will respond as quickly as I can.

If you have any concerns, please do contact me as well.

PLACE YOUR ORDER NOW!

Why Work With Me?


• Updates client regularly

• Friendly Communication

• Always online

• High-Quality Work

• Fast Delivery Time

.

pathfinder 1e – Can a Harbinger use Dark Claim on an animated object?

Assuming you are fighting said object, yes you can Claim non-sapients*

Dark Claim has “specific” (really, non-specific) targeting requirements; you must consider them an enemy.

As a swift action, the harbinger may Claim an opponent that she can see…

Other portions of the ability refer to Creatures, which is a game-term in Pathfinder

A harbinger can have a maximum number of creatures Claimed… may not Claim a creature she has already Claimed… (etc)

However, even non-sapient things (such as animated objects) are “creatures” in Pathfinder. Specifically, they are Construct creatures.


*It usually goes without saying, but the GM (not other party members) has the right and responsibility to interpret the rules in a way that they deem fun and fair. This probably means that they will agree that Dark Claim works fine on Constructs, but they could also rule that (for instance, to be realistic) it does not. If you have concerns about this type of ruling, I strongly recommend talking to your GM in an open way outside of game time.

object oriented – Resource management classes in C++ game

This is a part of simple sfml C++ game, but I think neither the library nor the language is that much crucial here. I am mainly worried about the design.

I have a class template ResourceHolder<Key, Resource> to hold one type of Resource such as texture or sound, inside a map. A key is usually an enum but can be anything.

I also have a class ResourceManager that keeps all available ResourceHolders in one place.

A simplified class diagram:

enter image description here

I am providing the full code for those classes:

ResourceHolder.h:

template <typename Key, typename Resource>
class ResourceHolder {
public:
    explicit ResourceHolder(std::string resourcesDir = "../resources/")
            : resourcesDir{std::move(resourcesDir)}
    {}

    template <typename... Args>
    void insert(const Key& key, Args&&... args) {
        auto resPtr = std::make_unique<Resource>();
        if (!resPtr->loadFromFile(resourcesDir + std::forward<Args>(args)...)) {
            msgErrorLoading(std::forward<Args>(args)...);
            ///* todo: should I e.g. "throw ErrorLoadingResource" here? */
        }
        resources.emplace(key, std::move(resPtr));
    }

    Resource& get(const Key& key) const {
        if (auto resource = resources.find(key); resource != std::end(resources)) {
            return *(resource->second);
        } throw std::invalid_argument{"No such resource id."};
    }

    void erase(const Key& key) noexcept {
        if (auto found = resources.find(key); found != std::end(resources)) {
            resources.erase(key);
        }
    }

    void eraseAll() {
        resources.clear();
    }

private:
    std::string resourcesDir;
    std::unordered_map<Key, std::unique_ptr<Resource>> resources;

public:
    template <typename... Args>
    ResourceHolder& operator+=(const ResourceInserter<Key, Args...>& inserter) {
        insert(std::move(inserter.key), std::move(std::get<Args>(inserter.args)...));
        return *this;
    }

    inline const Resource& operator()(const Key& key) const {
        return get(std::move(key));
    }

    inline Resource& operator()(const Key& key) {
        return get(std::move(key));
    }

    auto& getResources() const {
        return resources;
    }

    auto& getResourcesDir() const {
        return resourcesDir;
    }

    void setResourcesDir(std::string newPath) {
        resourcesDir = std::move(newPath);
    }

private:
    template <typename... Args>
    void msgErrorLoading(const Args... args) {
         std::cerr << "Failed loading resource: { Type: "" << typeid(Resource).name()<< "", File name: "";
        (std::cerr << ... << args) << "" }" << std::endl;
    }
};

ResourceManager.h:

class ResourceManager {
public:
    ResourceManager();

private:
    ResourceHolder<res::Texture, sf::Texture> textures;
    ResourceHolder<res::Sound, sf::SoundBuffer> sounds{"../resources/sound/"};

    void loadTextures();
    void loadSounds();

public:
    auto& getTextures() {
        return textures;
    }

    auto& getSounds() {
        return sounds;
    }
};

ResourceManager.cpp:

ResourceManager::ResourceManager() {
    loadTextures();
    loadSounds();
}

void ResourceManager::loadTextures() {
    textures.insert(res::Texture::Wizard, "wizard.png");
    textures.insert(res::Texture::Gray,   "gray.png");
    textures.insert(res::Texture::Orange, "orange.png");
}

void ResourceManager::loadSounds() {
    sounds += ResourceInserter(res::Sound::Bullet, "boing.wav");
    sounds += ResourceInserter(res::Sound::Bing,   "boing_long.wav");
    sounds += ResourceInserter(res::Sound::Poof,   "poof.wav");
}

ResourceInserter.h:

/** Operator += must take one argument
 *  This is a proxy class for operator+=
 *  You can use operator+= instead of insert() as an alternative insertion method
 */

template <typename Key, typename... Args>
class ResourceInserter {
public:
    explicit ResourceInserter(Key&& key, Args&&... args)
            : key{std::forward<Key>(key)}
            , args{std::forward<Args>(args)...}
    {}

    Key key;
    std::tuple<Args...> args;
};

template <typename T, typename... Args>
ResourceInserter(T&&, Args&&... args) -> ResourceInserter<T, Args...>;

Resources.h

namespace res {
    enum class Texture {
        Gray,
        Orange,
        Wizard
    };

    enum class Sound {
        Bullet,
        Poof,
        Bing
    };
}

Some basic usage (inside parent/caller/owner class):

auto wizardTexture = textures.get(res::Texture::Wizard);
auto bulletSound   = sounds(res::Sound::Bullet);

I am not asking for a deep-throughout review as I imagine it’d take too much off of your time.


I have few questions, answering any of them would be absolutely helpful.

  1. Whatever you think of that looks smelly or problematic, please do let me know.
  2. What’s wrong with my design from OOP/design patterns point of view? (I am especially worried about the part where I am inserting all the resources inside ResourceManager.cpp)
  3. What’s wrong with my code from C++ point of view? (I am especially interested in parts where I attempted using move semantics/perfect forwarding e.g. insert method or operator+=)
  4. Is there something confusing related to naming identifiers?

The reason why I am using enums as keys is that it works as a sort of connection interface for both insertion and then retrieval of the resource. If I insert a resource of key Enum_Type::Enum_Item, then I can also retrieve it using the same key.

I’d rather not hardcode the insertion process inside ResourceManager.cpp, and preferably keep it in a separate file, but the fact that I am using Enum as a key is kind of an obstacle here for me. Not sure how to fix it.


Thanks a lot!

All object In unreal Engine 4 Seen Green(Lit Mode)

IN UE4 all objects having green light effect object cannot see properly…
Including character in viewport seems greenish… In Lit mode

Object Oriented Design of Callback Methods

Assume that there is a library and it provides an interface to its users in order to callback them. Users implement this interface and receive notifications from the library.

Let’s say, ICallback is the interface, and Notify1(arg1), …, Notify5(arg5) are the interface methods.

interface ICallback;
+ Notify1(arg1)
+ ...
+ Notify5(arg5)

This library also provides a concrete class of the ICallback and distributes this class with the library package.

class CallbackAdapter : implements ICallback
+ Notify1(arg1)
+ ...
+ Notify5(arg5)

The owner of the library calls this concrete class as “adapter”. Users are encouraged to use this class instead of interface because it is claimed that;

a. You may not want to implement all notify methods 1 to 5 because you want to keep your code clean. If you extend this adapter class instead of implementing interface directly, then you can select methods to override. (This is the main motivation written in the class document)

b. If the interface is changed, say Notify6() is added, then user don’t have to change anything in the client code. No compilation error occurs when version is bumped. (This is an extra motivation suggested by people who extends adapter class)

Note that, some overridden methods of CallbackAdapter class aren’t just empty methods, they contain code, and do some work with objects provided by library (args).

This design really disturbs me. Firstly, I will explain why I’m not comfortable with it and then I will suggest a solution to above motivations. Finally, the question will be asked at the end.

1. Favor object composition over class inheritance

When user code extends CallbackAdapter, there will be coupling between user code and an external class.
This can break the user code easily since encapsulation is terribly broken by inheriting an external class.
Anyone can have a look at Effective Java 1st Edition, Item 14 for more details.

2. Ambiguous adapter pattern

I think the adapter pattern is misused here unless this isn’t another pattern with an “adapter” postfix in the name.

As far as I know, the adapter pattern is used when there is an external alternative implementation that we want to use but our interface doesn’t match to use alternative solution directly. Hence, we write an adapter to gain capabilities of alternative implementation (adaptee).

For all the adapter examples that I’ve seen, there is an adaptation to a concrete class, a class which does a real job and have a capability. However, for the given example, the adaptation is against an interface but not a concrete class.

Is this a valid adapter as we know it? I don’t think so.

There is a statement at applicability section of adapter pattern in the book of GoF Design Patterns:

Use the Adapter pattern when you want to use an existing class, and its interface does not match the one you need.

I think developers misinterpreted the word “interface” in this statement. Author mentions of adaptee’s interface which eventually declares the methods of concrete adaptee class. It seems that developers thought like this: There will be a class that a user created, this class will implement the interface provided by us (as library developers), user will want to use this existing class now and then, one day we will change interface, and won’t match with user code, so that we must provide an adapter, and distribute this adapter with our library.

I have just tried to understand the motivation of this adapter design. Above reasoning may be wrong but this doesn’t make code safer, it’s still insecure because of 1.

3. Distribution of adapter class

If there will be an adapter class, it shouldn’t be in the library package, it should be in the user package, this makes more sense to me because user adapts his code to work with new implementations.

4. It’s not good to break contract silently

Interfaces define behavior and are used to make contracts among participants. If a contract ends and a new contract starts, I think both sides must be aware of this change. Breaking a contract silently as given in the above example, may produce undefined behavior that we can’t notice at compile time but encounter on run time.

Solutions to Motivations

a. Just override methods and keep them empty if you don’t want to do anything with them.

If user can work without new method, Notify6(), this smells like a large interface problem. A segregation may be considered.

If you insist to have such a feature, you can design a callback register mechanism. Users can register any method they want. May register any of them, all of them or none of them. Keep function objects in the library, and callback registered functions. This seems a better OOP design compared to using inheritance.

b. Just avoid silent contract breaks. If an interface changes, it’s more secure to see compilation errors and solve them one by one at compile time.

Discussed design is currently in use in a widely used open source project. I’ve explained thoughts in my mind about it. All of them seems sensible to me.

I don’t think discussed motivations are huge gain. I can’t understand why does someone take the risks given at 1 and 4. Help me to understand advantages of such design. What am I missing here?