Example of Good Foreign Object Handling

Date: 2025 10-October 30

That is a comprehensive request! You're looking for a rigorous, side-by-side comparison of Query (Calculation) methods versus Setter (Command) methods, and how the principle of Encapsulation applies across different method types (static, class, instance), especially concerning foreign objects.

Here is a full analysis using a sample Client class.


1. 🔍 Core Concepts

Concept Description
Query A method that returns a value but does not change the state of the object (self) or the class (cls).
Setter (Command) A method that changes the state of the object (self) or the class (cls) but does not typically return a useful value (often returns None or self).
Encapsulation The principle that an object's internal state (attributes) should only be accessed or modified by the object's own methods.
Foreign Object Violation A method on one object (A) reaching into and modifying the state of another object (B) directly. This breaks Encapsulation.

2. 🆚 Query vs. Setter Analysis by Method Type

The primary distinction between Query and Setter is what the method acts upon and what it returns.

A. Instance Methods (Standard OOP)

Pattern Query (Calculation) Setter (Command)
Example client.get_status() client.set_status('active')
Code def get_status(self): return self.status def set_status(self, status): self.status = status
Encapsulation Good. Accesses self's state but only returns it. Good. Modifies self's state via its own method.

B. Class Methods (@classmethod)

Pattern Query (Class Data) Setter (Class State Change)
Example Client.get_max_limit() Client.set_max_limit(500)
Code def get_limit(cls): return cls.MAX_LIMIT def set_limit(cls, limit): cls.MAX_LIMIT = limit
Encapsulation Good. Accesses cls state via the defined method. Good. Modifies cls state via the defined method.

C. Static Methods (@staticmethod)

Pattern Query (Utility Calculation) Setter (Not Applicable)
Example Client.validate_input(data) N/A
Code def validate(data): return data > 0 Cannot access or modify self or cls state. It can only modify objects passed into it (see Section 3).
Encapsulation N/A. Does not interact with class or instance state. N/A.

3. 🛡️ Foreign Object Handling: Encapsulation

This section addresses the crucial difference between passing a foreign object as data and using a method to change its state.

A. Foreign Object Violation (BAD Practice) ❌

This breaks encapsulation because Client's method is managing Other's state.

Method Type Violation Example Why it's a Violation
Instance client.update_other(other): other.value = 10 client is reaching into the internal state of the other object directly. The Other object loses control over its state transitions.
Static Client.update_other(other): other.value = 10 The static method is acting as a global function to mutate the other object, bypassing other's own methods.

B. Good Foreign Object Handling (GOOD Practice) ✅

This respects encapsulation because Client's method uses the foreign object's own defined interface (its methods) to request a change, or simply uses it as data.

Method Type Good Handling Example Why it's Good
Instance client.process_other(other): other.request_update(client.data) client tells other what to do (request_update), but other's method decides how to change its internal state.
Static Client.get_data_from_other(other): return other.report() The method uses other as a data source (a Query) but does not attempt to modify its state.

4. 📝 Code Example Synthesis

Here is how you would use these principles in a single Client class, using an Other object.

Python

class Other:
    def __init__(self, value):
        self._internal_value = value
    
    # The only way to change the value (GOOD ENCAPSULATION)
    def set_value(self, new_value):
        print(f"[Other] State changing from {self._internal_value} to {new_value}")
        self._internal_value = new_value

class Client:
    MAX_COUNT = 100 
    
    def __init__(self, count=0):
        self.count = count

    # GOOD: Instance Method (Setter)
    def increment(self, step):
        """Changes only the state of self."""
        self.count += step
        
    # BAD: Instance Method (Foreign Object Violation) ❌
    def violate_other(self, other: Other, new_value):
        # Direct modification of a foreign object's internal attribute
        other._internal_value = new_value # VIOLATION!

    # GOOD: Instance Method (Good Foreign Object Handling) ✅
    def update_other_safely(self, other: Other, new_value):
        # Delegates the state change to the 'other' object itself
        other.set_value(new_value) 
        
    # GOOD: Static Method (Utility Query)
    @staticmethod
    def calc_new_limit(base: int) -> int:
        """Utility that calculates a value without touching state."""
        return base * 2
    
    # GOOD: Class Method (Class Setter)
    @classmethod
    def set_max_count(cls, new_max):
        """Changes only the state of the class."""
        cls.MAX_COUNT = new_max