Oop 如果可以,我们应该使用接口方法吗?
这个问题有点假设性。假设我有一个绘制树的应用程序。My structure controller实现了ITree接口,该接口使用诸如getChildren()、getParent()之类的方法来描述普通树。。。应用程序的某些部分只需要知道结构实现了ITree,这样它就可以查找它的子级或父级。因此,getParent()的高度足以返回ITree类型的对象。因此getChildren()可以返回ITree对象的集合 但是:) 如果在假设的TreeNode类中,我想对节点的子节点执行一些特定的操作,该怎么办。如果我使用ITree的getChildren()函数,我必须将它们转换为TreeNode,以便能够调用适当的实例函数(ITree未定义)。或者,我可以使用自己的迭代器遍历子节点,并尽我所能(因为这种方式实际上是树节点) 所以问题是:是否建议在每次可能的时候都使用接口函数,或者特定于对象的操作有时有意义 更新:[添加插图] (这是AS3语法,但重点是结构。) 下面是ITree:Oop 如果可以,我们应该使用接口方法吗?,oop,interface,Oop,Interface,这个问题有点假设性。假设我有一个绘制树的应用程序。My structure controller实现了ITree接口,该接口使用诸如getChildren()、getParent()之类的方法来描述普通树。。。应用程序的某些部分只需要知道结构实现了ITree,这样它就可以查找它的子级或父级。因此,getParent()的高度足以返回ITree类型的对象。因此getChildren()可以返回ITree对象的集合 但是:) 如果在假设的TreeNode类中,我想对节点的子节点执行一些特定的操作,该
public interface ITree {
function getParent():ITree;
}
这是我的TreeNode课程:
public class TreeNode implements ITree {
private var parent:TreeNode
public function getParent():ITree {
return parent;
}
function foo():void {}
function bar():void {
// Version 1 - using the interface
(getParent() as TreeNode).foo();
// Version 2 - using custom object accessor
parent.foo();
}
}
哪一个更好:版本1还是版本2
谢谢您需要随时随地使用ITree接口,以减少耦合。如果您需要接口未提供的功能,请使用TreeNode对象,但尽量避免强制转换操作 一旦通过将对象作为其超级类型之一传递而忘记了对象的真实类型,就没有安全的方法将其取回,因为: 子类型实例是一个超类型实例 但是 超类型实例不是子类型实例 因此,从逻辑上讲,您不能从超级类型实例返回到子类型实例——至少在没有任何安全保证的情况下 唯一的解决方法是在需要执行子类型操作时记住子类型。如果您的语言支持协变返回类型,则可以使用协变返回类型来改进接口定义,这样子类型就不会不必要地丢失:
In ITree:
public function getParent():ITree
In TreeNode:
public function getParent():TreeNode
这样,当您在TreeNode上调用getParent()时,您得到的是TreeNode,而不是ITree。当然,如果在声明为ITree的同一个实例上调用getParent(),则返回一个ITree。一旦忘记了类型信息,就太晚了
在类内部,您可以选择处理实类型。您仍然可以在接口中与外部世界对话(故意丢失超级类型信息),但实现可以处理实类型而不是接口
我在用Java做一些代码的实验。如果您感兴趣,请点击这里:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
public class TestTree {
@Test
public void testGetDepth() {
ITreeNode bigTree = TreeNode.create(null, 10);
ITreeNode left = bigTree.getChildren().get(0);
Assert.assertEquals(10, bigTree.getHeight());
Assert.assertEquals(9, left.getHeight());
Assert.assertEquals(0, bigTree.getDepth());
Assert.assertEquals(1, left.getDepth());
}
}
interface ITree {
List<? extends ITree> getChildren();
ITree getParent();
}
interface ITreeNode extends ITree {
@Override
List<? extends ITreeNode> getChildren();
int getDepth();
int getHeight();
}
class TreeNode implements ITreeNode {
private ITreeNode m_parent;
private final TreeNode m_left;
private final TreeNode m_right;
private final List<ITreeNode> m_children;
public static ITreeNode create(ITreeNode parent, int depth) {
TreeNode node = createDescendants(depth);
node.setParents(parent);
return node;
}
private static TreeNode createDescendants(int depth) {
if (depth == 0) {
return new TreeNode(null, null, null);
}
else {
return new TreeNode(null, TreeNode.createDescendants(depth - 1), TreeNode.createDescendants(depth - 1));
}
}
private TreeNode(ITreeNode parent, TreeNode left, TreeNode right) {
m_parent = parent;
m_left = left;
m_right = right;
List<ITreeNode> children = new ArrayList<ITreeNode>();
children.add(left);
children.add(right);
m_children = Collections.unmodifiableList(children);
}
private void setParents(ITreeNode parent)
{
m_parent = parent;
if (m_left != null)
(m_left).setParents(this);
if (m_right != null)
m_right.setParents(this);
}
public List<? extends ITreeNode> getChildren() {
return m_children;
}
public ITreeNode getParent() {
return m_parent;
}
public int getDepth() {
int depth = 0;
if (m_parent != null) {
depth = m_parent.getDepth() + 1;
}
return depth;
}
public int getHeight() {
int leftHeight = (m_left == null) ? 0 : m_left.getHeight() + 1;
int rightHeight = (m_right == null) ? 0 : m_right.getHeight() + 1;
return Math.max(leftHeight, rightHeight);
}
}
import java.util.ArrayList;
导入java.util.Collections;
导入java.util.List;
导入org.junit.Assert;
导入org.junit.Test;
公共类测试树{
@试验
公共void testGetDepth(){
ITreeNode bigTree=TreeNode.create(null,10);
ITreeNode left=bigTree.getChildren().get(0);
Assert.assertEquals(10,bigTree.getHeight());
Assert.assertEquals(9,left.getHeight());
Assert.assertEquals(0,bigTree.getDepth());
Assert.assertEquals(1,left.getDepth());
}
}
接口ITree{
列表您如何看待定制继承接口,例如:
public interface ITree {
function getParent():ITree;
}
如果我有一个CustomTreeNode类(,它实现了ICustomTreeNode),那么我将创建一个新的ITree子接口:
public interface ICustomTree extends ITree {
function getCustomParent():CustomTreeNode;
}
这样,我就可以使用正确类型的对象。很难想象你在讨论什么。你能发布代码/伪代码来说明你在说什么吗?我同意减少耦合并避免强制转换,这就是为什么这不是一个明显的问题,至少对我来说。我想应该有第三种方法来解决它,如果它有ge的话一般方法。如果需要使用函数foo(),则版本2更可取或将此函数添加到接口。接口假设任何对象都可以实现它,因此如果有人添加CustomTreeNode,则会导致错误。我不确定是否将这些函数添加到接口。例如,受保护的方法不应可见,尽管它们正在执行重要的内部任务。Tha不幸的是,在AS3中,没有办法实现Java、C#等泛型类型,也不能使用使用子类型的重写函数。