在过去的几年里,我一直在处理我们在对象层次结构中遇到类似问题的项目,这些问题总是会导致问题。我很好奇,如果有人知道经典的OOP(Java,C#,PHP5等)设计模式可以优雅地处理这种情况。
假设我们有一个现有的系统。除其他外,该系统具有两种类型的实体,每种实体都用单独的类建模。我们说
客户
的SalesRepresentative
由于历史原因,这些类都不从相同的基类继承或共享公共接口。
我看到的问题是,不可避免地会出现一个新功能,要求我们将Customer和SalesRepresentative视为相同类型的Object。我在过去看到这种处理的方式是创建一个包含两者成员变量的新类,然后每个方法将根据设置的不同对对象进行操作
//pseudo PHPish code
class Participator
{
public $customer;
public $salesRepresentative;
public function __construct($object)
{
if(object is instance of Customer)
{
$this->customer = $object;
}
if(object is instance of SalesRepresentative)
{
$this->salesRepresentative = $object;
}
}
public function doesSomething()
{
if($customer)
{
//We're a customer, do customer specific stuff
}
else if($salesRepresentative)
{
//We're a salesRepresentative, do sales
//representative specific stuff
}
}
}
有没有更优雅的方式来处理这种情况?
答案 0 :(得分:8)
也许这里可以使用Wrapper。创建一个Wrapper接口,说参与者指定新功能并为每个类构建具体的Wrappers,比如说实现新功能的CustomerWrapper和SalesRepresentativeWrapper。
然后简单地将对象包装在适当的包装器中,并编写以ParticipatorWrapper为目标的代码。
更新:Javaish代码:
interface ParticipatorWrapper{
public void doSomething();
}
class CustomerWrapper implements ParticipatorWrapper{
Customer customer;
public void doSomething(){
//do something with the customer
}
}
class SaleREpresentativeWrapper implements ParticipatorWrapper{
SaleRepresentative salesRepresentative;
public void doSomething(){
//do something with the salesRepresentative
}
}
class ClientOfWrapper{
public void mymethod(){
ParticipatorWrapper p = new ParticipatorWrapper(new Customer());
p.doSomething();
}
}
答案 1 :(得分:2)
这是文森特答案的替代方案,采取了相反的方法。正如我在下面提到的那样,有一些缺点,但是您的具体问题可能会消除这些问题,我认为这种解决方案在这些情况下更简单(或者您可能希望使用此解决方案和Vincent的某些组合)。
不是包装类,而是在类中引入钩子,然后将它们传递给函数。如果你想要从两个类中使用相同的数据做同样的事情(我猜你是基于这两个类没有共享的超类),这是一个合理的选择。
这是使用Visitor而不是Wrapper。 Java是这样的:
public <Output> Output visit(Vistor<Output> v) {
return v.process(...all shared the fields in Customer/SalesRep...);
}
然后你有一个访问者界面,你的所有功能都继承了这个界面:
interface Visitor<Output> {
public Output process(...shared fields...);
}
有些方法可以删除传递给访问者的内容,但是需要引入新的类来指定要使用的输入,无论如何都要包装,所以你不妨使用Vincent的答案。
这个解决方案的缺点是如果你做了改变类字段结构的事情,你可以自己购买很多重构,这在Vincent的答案中不是问题。如果您对Customer / SalesRep实例中存储的数据进行修改,这个解决方案也会有所帮助,因为您实际上必须将这些数据包装在访问者中。
答案 2 :(得分:1)
我认为您可以将mixins的概念应用于您的课程,以获得您想要的功能。