使用装饰器模式的设计问题

时间:2019-06-01 13:18:55

标签: java design-patterns instanceof decorator-pattern

所以,这是我的设计。 AccessDecorator类引用了另一个Access,就像普通的装饰器模式一样。

design

但是问题是当我创建包裹AccessDecorator的{​​{1}}并尝试查看访问类型时:

ConcreteAccess

这当然是行不通的,因为Access access = new InAllowedAccess(); Access wrapperAccess = new MismatchAccess(access); if (wrapperAccess instanceof InAllowedAccess) //this condition could be used to be a predicate for a filtering over an access list for example //do something 的类型不是wrapperAccess但是我真正想知道的是装饰器包装的具体访问的类型。

我考虑过在InAllowedAccess类中实现诸如isInstanceofInAllowed()isInstanceofOutAllowed()isInstanceofInDenied()isinstanceofOutDeniedd()之类的方法,但似乎不是一个好的解决方案,我不知道不知道...

否则,我应该为每种四种类型AccessInAllowedAccessOutAllowedAccessInDeniedAccess创建装饰器类吗?

还有其他更好的设计吗?

2 个答案:

答案 0 :(得分:0)

避免类型检查通常是做事的最佳方法。不幸的是,您没有足够的上下文了解如何使用类,因此我可以举一个示例说明如何使用多态性并避免这种情况。

添加类型检查将限制系统的增长能力,因为随着添加新类,这些类型需要包含在类型检查中。有时这可能会导致错误,因为您的代码可以假设类的数量或类型。这是一个示例:

注意:我只是为了说明目的而编造此内容。这并不是要表达您的逻辑或类似的东西。

public void someMethod(Access access) {

    if(access instance of InAccess) { 
        InAccess inAccess = (InAccess)access;
    }
    else {
        OutAccess outAccess = (OutAccess)access;
    }
}

启动时,系统有两个从Access继承的类。假设我们向系统添加了另一个Access class。该代码将在其他地方崩溃,因为我们可能会传递新的第三种访问类型,并且强制转换将不会成功。

当然,并非总是如此。有时,您所拥有的课程数量不会增加太多。有可能您可以预测将拥有的所有类型。

当然,由于所有事情都可能在编程中发生,所以有时您确实需要知道所使用的对象的类型。

让我们假设您的系统确实需要知道对象的类型。这是两种解决方案:

  1. 添加一个代表您拥有的所有类型的枚举。

public enum AccessType { InAccessAllowed, InAccessDenied, OutAccessDenied, // other types }

public interface Access {
   AccessType getType();
   // other stuff
}

这样,您将使用enum AccessType代替类型转换。

  1. 使用界面。

代替使用类来为每种Access定义一个接口。然后,您将检查接口而不是类。这样,您的装饰器可以实现与其装饰的类相同的接口。

public interface InAllowedAccess { }

public class InAllowedAccessImp implements InAllowedAccess { }

public class InAllowedAccessDecorator implements InAllowedAccess { }

我只是不提供替代实现的示例。由于描述中缺少上下文,因此我将尝试猜测如何使用类并向其添加行为。只是一个想法而已。

让我们假设您的系统向用户授予访问权限。可以为用户提供“进出”访问权限,并且系统的某些部分需要询问是否授予或拒绝了特定用户的访问权限,以便它可以执行特定逻辑。

如果您的Access classes没有任何行为,则可以将其用作描述符,该描述符将携带其他类完成其工作所需的信息。

public enum PortType { In, Out }
public enum Permissions { Allowed, Denied }

public class Access {
    private PortType mPortType;
    private Permissions mPermissions;

    public Access(PortType portType, Permissons permissions) {
        mPortType = portType;
        mPermissions = permissions;
    }

    public PortType getType() { return mPortType; }
    public Permissions getPermissions() { return mPermissions; }
}

如果您确实有行为,则可以使用多态。在Access interface中定义行为,并让妨碍该接口的类定义行为。

比方说,我们有一个消息系统,用户可以接收(发送)和发送(发送)消息。这些消息通过一个通道。这些通道将接受或拒绝消息。这是使用多态而不是类型检查的一种方法。

public interface MessageChannel {

    public bool canSendMessages(); // out
    public bool canReceiveMessages(); // in

    public void receiveMessage(Message m);
    public void sendMessage(Message m);
}

public class InMessageChannel implements MessageChannel {

    // out messaging is not allowed, cannot send
    public bool canSendMessages() { return false; } 

    // In messaging allowed, can receive
    public bool canReceiveMessages() { return true; } 

    public void sendMessage(Message m) {
        throw new SendingMessagesIsNotAllowd();
    }
    public void receiveMessage(Message m); { 
        // do something with the mssage
    }
}

public class OutMessageChannel implements MessageChannel {

    // out messaging allowed
    public bool canSendMessages() { return true; } 

    // In messaging not allowed
    public bool canReceiveMessages() { return false; } 

    public void sendMessage(Message m) {
        // send the message
    }

    public void receiveMessage(Message m); { 
        throw new ReceivingMessagesIsNotAllowd();
    }
}

如您所见,每个MessageCahnnel都有相应的行为。如果允许,它可以发送接收消息。这样,使用MessageChannel的其他类就不必进行类型转换。

答案 1 :(得分:0)

  

我考虑过在Access类中实现isInstanceofInAllowed(),isInstanceofOutAllowed(),isInstanceofInDenied()和isinstanceofOutDeniedd()之类的方法,但似乎不是一个好的解决方案,我不知道...

你是对的。那是一个不好的解决方案。接口通常属于软件中具有较高抽象水平的层,因此其方法列表应稳定。如果您在Access界面中添加了诸如此类的方法,则该界面将非常不稳定,因为将来很可能会在其中添加更多此类方法。

解决您问题的最简单方法是在core()接口中添加(仅一次)名为Access的新方法。每个装饰器都通过返回包装的/核心对象来实现此方法。

interface Access {
    ...
    Access core();
}

Access a = ...
if (a.core() instanceof ...