2017-03-03 42 views
-1

我和我的一位同事试图解决以下问题:这是反模式的一个例子吗?

让我们班的一个示例的 我的一个同事正面临着从A 提取一个特定的属性从一个特定抓取一个属性的问题类(在这种情况下,A)很容易。但假设 假设您有多个类(A1,A2 ...),并且您想从这些类的集合中获取一个具有越来越多的代码重用性的特定属性。

例如

public class A { 
    private String name; 
    . 
    . 
    . 
} 
List<String> listOfNames = createNameList(listOfAInstances); 

createNameList()方法将像以下:

List<String> tempList = new ArrayList<>(); 
for(A a : listOfAInstances) { 
    tempList.add(a.getName()); 
} 
return tempList; 

现在,如果有多个类我不得不为每个类和不同的属性做到这一点。

我建议两种方法:基于

  1. 思考方法。
  2. 创建一个名为“PropertyExtractable”的接口,并在其中放入一个名为“extractProperty”的方法。

如下图所示:

interface PropertyExtractable { 
    Object extractProperty(); 
} 

public class A implements PropertyExtractable { 
    private String name; 
    . 
    . 
    . 
    public Object extractProperty() { 
     return this.name; 
    } 
} 

为此,我可以写,然后可以随处即

public Object getPropertiesOfPropertyExtractable(PropertyExtractable prExtractable) { 
     return prExtractable.extractProperty(); 
    } 

这是背景中使用的一些实用的方法,矿井中的一个其他同事曾对第二种方法有不同的看法,他告诉我这似乎是反模式。他试图向我解释,但我没有完全理解,所以我在这里问。

我想比较这个例子与Java中的Comparator接口。像java允许我们在任何自定义对象类上使用比较器,并允许我们定义用于比较的逻辑,那么为什么我无法定义提取的逻辑

更多更多的接口可以这种方式使用,那么为什么我们不应该用它

我想知道的是这种方法是反模式吗?为什么?

+1

嗯,我的第一个想法是,它不是类型安全的。然后,如果您可以拥有不同类别的列表,那么您已经需要拥有这些类别的通用界面。为什么不在其中包含一个'String getName()'? – Fildor

+1

如果您的示例代码和“例如”文本与他们的类名匹配,它会有很大的帮助。 –

+1

不要忘记,您可以在重写的方法中使用更具体的返回类型:''中的'public String extractProperty()'''。然后,如果你有一个'A'的引用,你可以编写'String name = myA.extractProperty();',而不需要强制转换。 –

回答

0

您可以将提取的代码在不同的方法和重用:

class A { 
    private String name; 

    public String getName() { 
     return name; 
    } 
} 

class B { 
    private String surname; 

    public String getSurname() { 
     return surname; 
    } 
} 

public class SomeClass { 

    private <T> List<String> extractFields(List<T> list, Function<T, String> extractorFunction) { 
     return list.stream().map(extractorFunction).collect(Collectors.toList()); 
    } 

    public void someMethod() { 

     List<A> listOfInstancesA = new ArrayList<>(); 
     List<B> listOfInstancesB = new ArrayList<>(); 

     // fill lists 

     List<String> fieldsA = extractFields(listOfInstancesA, A::getName); 
     List<String> fieldsB = extractFields(listOfInstancesB, B::getSurname); 
    } 
} 
+0

我发布这个问题的原因不是找到问题的解决方案,而是找到正确的方法来做到这一点。正如我所提到的,我已经为此定义了两种方法,我可以选择其中任何一种方法,但我相信它会起作用。 –

+0

我的建议既不反思也不创建界面,这就是为什么我建议你这样做。它不会触及初始类A和B. –

+0

感谢这种新方法:)但我认为它是更一般的问题,我在这里使用Java是因为我知道这一点,但让我们假设如果同样的事情在Swift/JavaScript或任何其他语言。 –

0

你描述正在与你不想改变原有系统的情况。

因为如果你不是,你会引入一个公共属性的接口(比如你的比较器接口的例子)。你引入了一个没有意义的接口,它可能是一个反模式,因为你实际上需要一个功能接口:PropertyExtractable vs. NamedObject =>有一个方法:String getName())。

如果您想要实现反射,那么您的界面可能是正确的,但我没有看到它(例如,在你的情况下,你已经内置到Java中的反射)。

通常情况下,您使用Adapter模式从未实现请求的接口的对象获取属性/方法。

+0

我不理解这部分“你引入了一个没有意义的接口”在这种情况下,我应该寻找什么确切的“含义”? –

+0

您已移至抽象级别,此类接口的使用是普遍的:例如这就是我用例的意思,如果你想创建一个反射方法,那么它是可以的,因为Reflection对代码的实际结构(对象,类,属性等)起作用。但是你的用例是具体的(命名对象)源于具体的领域。您必须查找域的公共属性以及是否可以从中派生接口(我的示例是NamedObject接口)。 – PsiX

+0

我的属性并不常见(不能将它们移动到一个通用的接口),但是我希望所有类的通用行为在被调用时可以返回特定属性(已经决定)应该返回,整个问题的基础是因为我的一个同事在斯威夫特有8到10个班,他想从中提取一个特定的属性在屏幕上显示(可能在下拉菜单中)。所以正如我所提到的,可能有两种方法,反射/使用接口来强制每个实现使用这种获取属性的行为。 –