首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java (Android)中多项继承的适当解决方法

Java (Android)中多项继承的适当解决方法
EN

Software Engineering用户
提问于 2012-12-23 12:50:42
回答 5查看 10.9K关注 0票数 16

在正确的代码实现方面,我遇到了一个概念性问题,这似乎需要多个继承,在许多面向对象语言中这不是一个问题,但由于该项目是针对Android的,所以没有像多个extends这样的东西。

我有很多来自不同基类的活动,比如简单的ActivityTabActivityListActivityExpandableListActivity等等。在所有活动中,我还需要将一些代码片段放入onStartonStoponSaveInstanceStateonRestoreInstanceState和其他标准事件处理程序中。

如果我有一个用于所有活动的基类,我会将代码放入一个特殊的中间派生类中,然后创建扩展它的所有活动。不幸的是,情况并非如此,因为有多个基类。但是,将相同的代码部分放入几个中间类并不是一件容易的事,imho。

另一种方法可以是创建一个helper对象,并将上述事件的所有调用委托给助手。但这需要包含helper对象,并在所有中间类中重新定义所有处理程序。因此,这里的第一种方法并没有太大的区别--仍然有很多代码重复。

如果类似的情况发生在Windows下,我会将基类子类(与安卓中的Activity类“对应”的东西),并在那里捕获适当的消息(在一个地方)。

在Java/Android中可以做些什么呢?我知道有一些有趣的工具,比如Java仪器仪表 (有一些真实的例子),但我不是一个Java大师,也不确定在这个特定的情况下是否值得尝试。

如果我错过了其他一些像样的解决方案,请提出来。

更新:

对于那些有兴趣在Android中解决同样问题的人,我找到了一个简单的解决办法。存在应用程序类,它除其他外提供接口ActivityLifecycleCallbacks。它正是我所需要的,允许我们拦截并为所有活动的重要事件增加一些价值。这种方法的唯一缺点是它可以从API级别14开始使用,这在很多情况下是不够的(支持API级别10是当今的一个典型需求)。

EN

回答 5

Software Engineering用户

回答已采纳

发布于 2012-12-23 15:38:58

在android/java中,如果没有代码复制,恐怕无法实现您的类系统。

但是,如果将特殊的中间派生类与复合助手对象组合在一起,则可以将代码复制最小化。这被称为装潢工_模式

代码语言:javascript
运行
复制
    class ActivityHelper {
        Activity owner;
        public ActivityHelper(Activity owner){/*...*/}
        onStart(/*...*/){/*...*/}   
    }

    public class MyTabActivityBase extends TabActivity {
        private ActivityHelper helper;
        public MyTabActivityBase(/*...*/) {
            this.helper = new ActivityHelper(this);
        }

        protected void onStart() {
            super.onStart();
            this.helper.onStart();
        }
        // the same for onStop, onSaveInstanceState, onRestoreInstanceState,...
    }

    Public class MySpecialTabActivity extends MyTabActivityBase  {
       // non helper logic goes here ....
    }

因此,您创建的每个基类都会创建一个中间基类,它将其调用委托给助手。中间基类是相同的,但它们所继承的基类除外。

票数 6
EN

Software Engineering用户

发布于 2012-12-23 20:18:36

我想你是想避免错误的代码复制。我相信迈克尔·羽毛写了一篇关于这个的文章,但不幸的是我找不到它。他描述它的方式是,您可以认为您的代码有两个部分,如橘子:果皮和果肉。rind是类似于方法声明、字段声明、类声明等的东西。纸浆是这些方法内部的东西;实现。

当谈到干燥,你想避免重复纸浆。但通常在这个过程中,你会创造更多的牛皮。这没什么。

下面是一个例子:

代码语言:javascript
运行
复制
public void method() { //rind
    boolean foundSword = false;
    for (Item item : items)
        if (item instanceof Sword)
             foundSword = true;
    boolean foundShield = false;
    for (Item item : items)
        if (item instanceof Shield)
             founShield = true;
    if (foundSword && foundShield)
        //...
}  //rind

这可以重构为以下内容:

代码语言:javascript
运行
复制
public void method() {  //rind
    if (foundSword(items) && foundShield(items))
        //...
} //rind

public boolean foundSword(items) { //rind
    return containsItemType(items, Sword.class);
} //rind

public boolean foundShield(items) { //rind
    return containsItemType(items, Shield.class);
} //rind

public boolean containsItemType(items, Class<Item> itemClass) { //rind
    for (Item item : items)
        if (item.getClass() == itemClass)
             return true;
    return false;
} //rind

我们在这个重构中增加了大量的外皮。但是,第二个例子有一个更干净的method(),它的干法违规较少。

您说过要避免使用装饰图案,因为它会导致代码重复。如果您查看该链接中的图像,您将看到它将只复制operation()签名(即: rind)。对于每个类,operation()实现(纸浆)应该是不同的。我认为您的代码最终会变得更干净,并减少纸浆复制。

票数 6
EN

Software Engineering用户

发布于 2012-12-23 16:52:22

比起继承,你应该更喜欢组合。一个很好的例子是IExtension WCF框架中的.NET "模式“。您有3个接口,IExtension、IExtensibleObject和IExtensionCollection。然后,您可以通过将作曲实例添加到IExtensibleObject对象的扩展IExtensionCollection属性中,使用IExtension对象进行不同的行为。在java中,它应该是这样的,但是,您不必创建自己的IExtensioncollection实现,在添加/删除项时调用附加和分离方法。还请注意,应该由您在可扩展类中定义扩展点,该示例使用类似事件的回调机制:

代码语言:javascript
运行
复制
import java.util.*;

interface IExtensionCollection<T> extends List<IExtension<T>> {
    public T getOwner();
}

interface IExtensibleObject<T> {
    IExtensionCollection<T> getExtensions();
}

interface IExtension<T> {
    void attach(T target);
    void detach(T target);
}

class ExtensionCollection<T>
    extends LinkedList<IExtension<T>>
    implements IExtensionCollection<T> {

    private T owner;
    public ExtensionCollection(T owner) { this.owner = owner; }
    public T getOwner() { return owner; }
    public boolean add(IExtension<T> e) {
        boolean result = super.add(e);
        if(result) e.attach(owner);
        return result;
    }
    // TODO override remove handler
}

interface ProcessorCallback {
    void processing(byte[] data);
    void processed(byte[] data);
}

class Processor implements IExtensibleObject<Processor> {
    private ExtensionCollection<Processor> extensions;
    private Vector<ProcessorCallback> processorCallbacks;
    public Processor() {
        extensions = new ExtensionCollection<Processor>(this);
        processorCallbacks = new Vector<ProcessorCallback>();
    }
    public IExtensionCollection<Processor> getExtensions() { return extensions; }
    public void addHandler(ProcessorCallback cb) { processorCallbacks.add(cb); }
    public void removeHandler(ProcessorCallback cb) { processorCallbacks.remove(cb); }

    public void process(byte[] data) {
        onProcessing(data);
        // do the actual processing;
        onProcessed(data);
    }
    protected void onProcessing(byte[] data) {
        for(ProcessorCallback cb : processorCallbacks) cb.processing(data);
    }
    protected void onProcessed(byte[] data) {
        for(ProcessorCallback cb : processorCallbacks) cb.processed(data);
    }
}

class ConsoleProcessor implements IExtension<Processor> {
    public ProcessorCallback console = new ProcessorCallback() {
        public void processing(byte[] data) {

        }
        public void processed(byte[] data) {
            System.out.println("processed " + data.length + " bytes...");
        }
    };
    public void attach(Processor target) {
        target.addHandler(console);
    }
    public void detach(Processor target) {
        target.removeHandler(console);
    }
}

class Main {
    public static void main(String[] args) {
        Processor processor = new Processor();
        IExtension<Processor> console = new ConsoleProcessor();
        processor.getExtensions().add(console);

        processor.process(new byte[8]);
    }
}

如果您能够在类之间提取公共扩展点,则这种方法具有扩展重用的好处。

票数 3
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/180459

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档