Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 什么';检查一个对象是否可以在不使用instanceof的情况下放到另一个对象上的最佳方法是什么?_Oop_Design Patterns_Instanceof - Fatal编程技术网

Oop 什么';检查一个对象是否可以在不使用instanceof的情况下放到另一个对象上的最佳方法是什么?

Oop 什么';检查一个对象是否可以在不使用instanceof的情况下放到另一个对象上的最佳方法是什么?,oop,design-patterns,instanceof,Oop,Design Patterns,Instanceof,我正在开发一个拖放形状编辑器。但是,我还需要一种将形状“连接”在一起的方法,其中只有特定的形状可以连接到其他特定的形状。例如,正方形只能连接到圆,而三角形可以连接到正方形和圆 所以我所做的就是创建一个超级类“Shape”,让所有其他的形状都是从Shape类继承的类的对象。在Shape类中,我放置了一个名为“canBeConnectedTo(Shape s)”的方法,该方法返回该特定对象是否可以连接到另一个特定对象,但我看到如何连接的唯一方法是使用instanceof操作符,这使我认为可能有更好的

我正在开发一个拖放形状编辑器。但是,我还需要一种将形状“连接”在一起的方法,其中只有特定的形状可以连接到其他特定的形状。例如,正方形只能连接到圆,而三角形可以连接到正方形和圆

所以我所做的就是创建一个超级类“Shape”,让所有其他的形状都是从Shape类继承的类的对象。在Shape类中,我放置了一个名为“canBeConnectedTo(Shape s)”的方法,该方法返回该特定对象是否可以连接到另一个特定对象,但我看到如何连接的唯一方法是使用instanceof操作符,这使我认为可能有更好的设计模式

目前,Square类实现如下方法:

boolean canBeConnectedTo(Shape s) {
    return s instanceof Circle;
}
我希望这样做,特定形状可以连接到的形状可以参数化,以便在运行时添加或删除它们。此外,它必须是可扩展的,以便在不更改代码的情况下轻松添加新形状。

我提出的另一种方法是,在每个Shape对象中创建一个实例变量,其中包含对象的形状类型,但这不是设计模式,这只是一种避免使用instanceof而不更改结构的方法

那么,我的想法从一开始就是有缺陷的,还是没有比上述替代方案更好的方法

我希望这样做,特定形状可以连接到的形状可以参数化,以便在运行时添加或删除它们

public class Shape {
      public Map<Type, Boolean> connections = new EnumMap<Type, Boolean>(Type.class);

      public Boolean canConnectTo(Shape shape) {
            Boolean canConnect = connections.get(shape.getType());

            if (canConnect == null)
              canConnect = false;

            return canConnect;
      }
}


public class Circle extends Shape {
      public Circle() {
            connections.put(typeof(Square), true);
            connections.put(typeof(Triangle), false);
      }
}


public class Square extends Shape {
      public Square() {
            connections.put(typeof(Circle), true);
            connections.put(typeof(Triangle), true);
      }
}

public class Triangle extends Shape {
      public Triangle() {
            connections.put(typeof(Circle), false);
            connections.put(typeof(Square), true);
      } 
}
在这种情况下,检查类型似乎是必要的。该类有方法
isAssignableFrom
isInstance
,它们是
instanceof
的反射等价物,或者如果不需要考虑子类型,则只使用
equals
方法(无论如何,建议避免扩展具体类)。使用它们,您可以有一个类来跟踪哪些形状可以连接到哪些形状(例如,使用类实例的映射),从而将该逻辑放在一个地方,而不是分散到形状的所有子类中

可以这样做,假设不使用子类化,这样我们就可以比较类是否相等。(免责声明:已编译,未测试)

import java.util.*;
公共类连接权限{
允许的私有最终集=新HashSet();
public void allowConnection(类从、类到){
添加(新连接(从、到));
}
公共无效禁止连接(类从、类到){
允许。删除(新连接(从,到));
}
允许公共布尔值断开连接(类从、类到){
允许返回。包含(新连接(从、到));
}
//也可以使用这样的方法来隐藏需要权限的详细信息
//基于对象的类型。
允许公共布尔值isConnectionAllowed(对象从、对象到){
返回isConnectionAllowed(从.getClass()到.getClass());
}
私有静态类连接{
私人期末c1班;
二等兵;
公共连接(c1类、c2类){
//如果连接不应对称,请消除此情况。
如果(c1.getName().compareTo(c2.getName())<0){
这1.c1=c2;
这是c2=c1;
}否则{
这1.c1=c1;
这1.c2=c2;
}
}
公共布尔等于(对象obj){
连接,即=(连接)obj;
返回this.c1.equals(that.c1)和this.c2.equals(that.c2);
}
公共int hashCode(){
int result=c1.hashCode();
result=31*result+c2.hashCode();
返回结果;
}
}
}

我会将可以相互连接的形状的逻辑分离到一个单独的对象(连接管理器)中,该对象可以在运行时配置。形状需要实现一个新的IConnectable接口。可以在运行时配置连接管理器,以指定可以连接哪些可连接件

示例C#代码(未测试):

//可连接类别*不需要*与形状类型耦合,
//但如果需要,可以为每个形状单独设置一个类别。
公共枚举可连接类别
{
广场
三角
}
//所有形状都将实现此接口。
可连接的公共接口
{
ConnectableCategory目录{get;}
}
//形状(或其他控制逻辑)可以访问连接管理器
//确定哪些可连接件可以相互连接。
公共接口IConnectionManager
{
布尔可连接(第一个可连接,第二个可连接);
}
//下面是一个连接管理器的示例。
公共类连接管理器:IConnectionManager
{
私人词典
许可连接=
新字典();
//配置连接管理器以允许在指定的
//可连接件的类别。
公共无效许可连接(
可连接类别第一,
可连接类别(秒)
{
HashSet许可目标;
if(this.permittedConnections.TryGetValue(首先,out permittedTargets))
{
许可目标。添加(第二个);
}
其他的
{
permittedTargets=新哈希集(){second};
this.permittedConnections.Add(首先是permittedTargets);
}
}
//测试两个可连接件是否可以连接。
公共bool CanConnect(第一个可连接,第二个可连接)
{
HashSet许可目标;
如果(此为.permittedConnections.TryGetValue(
首先,凯蒂托里,
出来
// The connectable categories don't *need* to be coupled with shape types,
// but you could have a separate category for each shape if required.
public enum ConnectableCategory
{
    Square,
    Triangle
}

// All shapes would implement this interface.
public interface IConnectable
{
    ConnectableCategory Catgetory { get; }
}

// Shapes (or other control logic) would have access to a connection manager
// which determines which connectables can be connected to each other.
public interface IConnectionManager
{
    bool CanConnect(IConnectable first, IConnectable second);
}

// Here's an example impelentation of a connection manager.
public class ConnectionManager : IConnectionManager
{
    private Dictionary<ConnectableCategory, HashSet<ConnectableCategory>>
        permittedConnections =
        new Dictionary<ConnectableCategory, HashSet<ConnectableCategory>>();

    // Configure the connection manager to permit connections between specified
    // categories of connectables.
    public void PermitConnection(
        ConnectableCategory first,
        ConnectableCategory second)
    {
        HashSet<ConnectableCategory> permittedTargets;
        if (this.permittedConnections.TryGetValue(first, out permittedTargets))
        {
            permittedTargets.Add(second);
        }
        else
        {
            permittedTargets = new HashSet<ConnectableCategory>() { second };
            this.permittedConnections.Add(first, permittedTargets);
        }
    }

    // Test if two connectables can be connected.
    public bool CanConnect(IConnectable first, IConnectable second)
    {
        HashSet<ConnectableCategory> permittedTargets;
        if (this.permittedConnections.TryGetValue(
            first.Catgetory,
            out permittedTargets))
        {
            return permittedTargets.Contains(second.Catgetory);
        }
        else
        {
            return false;
        }
    }
}
public class Shape {
      public Map<Type, Boolean> connections = new EnumMap<Type, Boolean>(Type.class);

      public Boolean canConnectTo(Shape shape) {
            Boolean canConnect = connections.get(shape.getType());

            if (canConnect == null)
              canConnect = false;

            return canConnect;
      }
}


public class Circle extends Shape {
      public Circle() {
            connections.put(typeof(Square), true);
            connections.put(typeof(Triangle), false);
      }
}


public class Square extends Shape {
      public Square() {
            connections.put(typeof(Circle), true);
            connections.put(typeof(Triangle), true);
      }
}

public class Triangle extends Shape {
      public Triangle() {
            connections.put(typeof(Circle), false);
            connections.put(typeof(Square), true);
      } 
}