You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建孙类排列组合?基于音频引擎Sound类的子类扩展需求

Great question! Since Java doesn’t support multiple inheritance, combining the features of LoopSound and MultiSound into a "grandchild" class requires some intentional design. Below are three practical approaches tailored to your audio engine, along with code examples and tradeoffs for each:

1. Extract Features to Interfaces (Flexible Base for Combinations)

First, abstract the unique behaviors of LoopSound and MultiSound into interfaces. This lets you mix-and-match features in any combination by having concrete classes implement multiple interfaces while inheriting from Sound.

Step 1: Define Interfaces

// Interface for loop-capable sounds
public interface Loopable {
    void setLoopCount(int count);
    void startContinuousLoop();
}

// Interface for multi-instance capable sounds
public interface MultiPlayable {
    void playNewInstance();
    void stopAllInstances();
}

Step 2: Refactor Existing Subclasses

Update your original subclasses to implement these interfaces (keeping their core logic):

public class LoopSound extends Sound implements Loopable {
    private int loopCount;

    public LoopSound(String filePath) {
        super(filePath);
    }

    @Override
    public void setLoopCount(int count) {
        this.loopCount = count;
        if (clip != null) {
            clip.loop(count);
        }
    }

    @Override
    public void startContinuousLoop() {
        setLoopCount(Clip.LOOP_CONTINUOUSLY);
        play();
    }
}

public class MultiSound extends Sound implements MultiPlayable {
    private List<Clip> activeClips = new ArrayList<>();

    public MultiSound(String filePath) {
        super(filePath);
    }

    @Override
    public void playNewInstance() {
        Clip newClip = createNewClip(filePath);
        activeClips.add(newClip);
        newClip.start();
    }

    @Override
    public void stopAllInstances() {
        activeClips.forEach(Clip::stop);
        activeClips.clear();
    }

    // Helper to create new Clip instances
    private Clip createNewClip(String filePath) {
        // Implement audio loading logic here
        return null;
    }
}

Step 3: Create Combined "Grandchild" Class

Now build a class that inherits from Sound and implements both interfaces, combining their logic:

public class LoopMultiSound extends Sound implements Loopable, MultiPlayable {
    private int loopCount;
    private List<Clip> activeClips = new ArrayList<>();

    public LoopMultiSound(String filePath) {
        super(filePath);
    }

    // Implement Loopable methods
    @Override
    public void setLoopCount(int count) {
        this.loopCount = count;
    }

    @Override
    public void startContinuousLoop() {
        setLoopCount(Clip.LOOP_CONTINUOUSLY);
        playNewInstance();
    }

    // Implement MultiPlayable methods with loop logic
    @Override
    public void playNewInstance() {
        Clip newClip = createNewClip(filePath);
        newClip.loop(loopCount);
        activeClips.add(newClip);
        newClip.start();
    }

    @Override
    public void stopAllInstances() {
        activeClips.forEach(Clip::stop);
        activeClips.clear();
    }

    private Clip createNewClip(String filePath) {
        // Reuse or implement clip creation logic
        return null;
    }
}

Pros: Highly flexible—easily add new features (like VolumeControllable) with new interfaces.
Cons: Minor code duplication across implementing classes (fixable with helper utility classes).

2. Use the Decorator Pattern (Dynamic Runtime Combinations)

If you need to mix features dynamically (e.g., turn a regular Sound into a loopable multi-instance sound at runtime), the decorator pattern is ideal. It lets you wrap Sound objects with feature-enhancing decorators.

Step 1: Create a Decorator Base Class

public abstract class SoundDecorator extends Sound {
    protected Sound wrappedSound;

    public SoundDecorator(Sound wrappedSound) {
        super(wrappedSound.filePath);
        this.wrappedSound = wrappedSound;
    }

    // Delegate basic play/stop to the wrapped sound
    @Override
    public void play() {
        wrappedSound.play();
    }

    @Override
    public void stop() {
        wrappedSound.stop();
    }
}

Step 2: Build Feature Decorators

// Loop feature decorator
public class LoopDecorator extends SoundDecorator implements Loopable {
    private int loopCount;

    public LoopDecorator(Sound wrappedSound) {
        super(wrappedSound);
    }

    @Override
    public void setLoopCount(int count) {
        this.loopCount = count;
        if (wrappedSound.clip != null) {
            wrappedSound.clip.loop(count);
        }
    }

    @Override
    public void startContinuousLoop() {
        setLoopCount(Clip.LOOP_CONTINUOUSLY);
        play();
    }
}

// Multi-instance feature decorator
public class MultiDecorator extends SoundDecorator implements MultiPlayable {
    private List<Clip> activeClips = new ArrayList<>();

    public MultiDecorator(Sound wrappedSound) {
        super(wrappedSound);
    }

    @Override
    public void playNewInstance() {
        Clip newClip = createNewClip(wrappedSound.filePath);
        activeClips.add(newClip);
        newClip.start();
    }

    @Override
    public void stopAllInstances() {
        activeClips.forEach(Clip::stop);
        activeClips.clear();
    }

    private Clip createNewClip(String filePath) {
        // Implement clip creation logic
        return null;
    }
}

Step 3: Combine Decorators at Runtime

// Create a base sound
Sound baseExplosion = new Sound("explosion.wav");

// Wrap it to add loop + multi-instance features
Sound loopMultiExplosion = new MultiDecorator(new LoopDecorator(baseExplosion));

// Use the combined features
((Loopable) loopMultiExplosion).startContinuousLoop();
((MultiPlayable) loopMultiExplosion).playNewInstance();

Pros: Dynamic combinations—no need to predefine every possible "grandchild" class.
Cons: Requires casting to access interface methods (unless you add helper methods in decorators).

3. Create Concrete Combined Subclasses (Simple for Fixed Combinations)

If you only need a small, fixed set of combinations (like just LoopMultiSound), directly extend one subclass and integrate the other's logic.

public class LoopMultiSound extends MultiSound implements Loopable {
    private int loopCount;

    public LoopMultiSound(String filePath) {
        super(filePath);
    }

    @Override
    public void setLoopCount(int count) {
        this.loopCount = count;
    }

    @Override
    public void startContinuousLoop() {
        setLoopCount(Clip.LOOP_CONTINUOUSLY);
        playNewInstance();
    }

    // Override playNewInstance to apply loop logic
    @Override
    public void playNewInstance() {
        Clip newClip = createNewClip(filePath);
        newClip.loop(loopCount);
        activeClips.add(newClip);
        newClip.start();
    }
}

Pros: Minimal boilerplate, straightforward to implement.
Cons: Doesn't scale—every new combination requires a new class.


内容的提问来源于stack exchange,提问作者CSDragon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:23:50