简体   繁体   English

设计问题:如何最好地使用构图

[英]DESIGN PROBLEM: How to use composition the best

I'm working on a project and have some doubts about it's design.我正在做一个项目,对它的设计有些怀疑。 How can I design the following problem the best (in JAVA):我怎样才能最好地设计以下问题(在 JAVA 中):

Class A with the following attributes: Class A具有以下属性:

  • HashSet of Pixels where each pixel has x,y coordinates and value v between 0-1. HashSet of Pixels,其中每个像素的 x,y 坐标和值 v 介于 0-1 之间。
  • instance of class B. class B 的实例。

Class B with the following function: Class B与以下 function:

  • a function that gets a Pixel and returns its left neighbor.一个 function 获取一个像素并返回其左邻居。

When I'm in class AI want to use B.function on each pixel in A and add it to the HashSet only if it's not already there.当我在 class 中时,AI 想在 A 中的每个像素上使用 B.function 并仅当它不存在时才将其添加到 HashSet 中。 The problem is that I don't want to send the HashSet to the function, how bad is it to return new instance of Pixel from the function if it might already exist (This function going to run on many pixels and will create many unused instances of Pixel).问题是,我不想将主题集发送到ZC1C425268E68385D1AB5074C174F14F14Z,从ZC1C425268E68E68385D1AB5074C174C17A94F14的情况下返回新的Pixel新实例(如果已经存在),那么它可能已经存在了这一点,这是有多糟糕的。像素)。

What other options do I have?我还有什么其他选择?

Since you use Set<Pixel> you have to create new Pixel instance to check if it exists in set or not.由于您使用Set<Pixel>必须创建新的Pixel实例来检查它是否存在于集合中。

If set contains N elements after calling B.function method you will create extra N Pixel nodes.如果在调用B.function方法后集合包含N个元素,您将创建额外的NPixel节点。 If all elements are new, you just add them to set, in other case Garbage Collection needs to sweep them.如果所有元素都是新的,您只需将它们添加到 set 中, Garbage Collection需要清除它们。 One of drawbacks is we need to create m (wheren m <= N - number of Pixel -s which already exists in set) and later we need to collect them by GC .缺点之一是我们需要创建m (其中m <= N - 集合中已经存在的Pixel -s 的数量),然后我们需要通过GC收集它们。 How big is m/N ratio depends from your algorithm and what you are actually doing. m/N比率有多大取决于您的算法和您实际在做什么。

Lets calculate how many memory we need to consume for N = 1_000_000 pixels in set.让我们计算在集合中N = 1_000_000像素需要消耗多少 memory。 We know that int is a 4 bytes and double is 8 bytes , lets add extra 8 bytes for an object and 8 bytes for a reference.我们知道int4 bytesdouble8 bytes ,让我们为 object 添加额外的8 bytes8 bytes作为参考。 It gives 32 bytes for every instance of Pixel object.它为Pixel object 的每个实例提供32 bytes We need to create N objects which gives 32MB .我们需要创建N个提供32MB的对象。 Let's assume that our ratio is 50% so, 16MB we allocated just to check it is not needed.假设我们的比率是50% ,所以我们分配16MB只是为了检查它是不需要的。

If this is a cost you can not pay you need to develop algorithm which allows you iterate over Set<Pixel> in an order from left-to-right .如果这是您无法支付的成本,则需要开发允许您按left-to-right的顺序迭代Set<Pixel>的算法。 So, left neighbour of Pixel X is before X .因此, Pixel X的左邻居在X之前。

Assume that left neighbour of Pixel X(x, y) is pixel X'(x - 1, y) .假设Pixel X(x, y)的左邻居是像素X'(x - 1, y) Pixel B(0, y) does not have left neighbour. Pixel B(0, y)没有左邻。 You need to use TreeSet and implement Comparable<Pixel> interface in Pixel class.您需要使用TreeSet并在Pixel class 中实现Comparable<Pixel>接口。 Simple implementation could look like this:简单的实现可能如下所示:

@Override
public int compareTo(Pixel o) {
    return this.y == o.y ? this.x - o.x : this.y - o.y;
}

This allows you to iterate set in order from left to right: (0, 0), (1, 0), ...., (x - 1, y), (x, y), (x + 1, y), ... , (maxX, maxY) .这允许您按从左到右的顺序迭代集合: (0, 0), (1, 0), ...., (x - 1, y), (x, y), (x + 1, y), ... , (maxX, maxY) So, when you iterate it you can check whether previous element is a left neighbour of current Pixel .因此,当您迭代它时,您可以检查前一个元素是否是当前Pixel的左邻居。 Example implementation could look like below:示例实现可能如下所示:

void addNeighboursIfNeeded() {
    Set<Pixel> neighbours = new HashSet<>(pixels.size());
    Pixel last = null;
    for (Pixel p : pixels) {
        if (p.getX() == 0 || p.isLeftNeighbour(last)) {
            // a left border pixel
            // or last checked element is a left neighbour of current pixel.
            last = p;
            continue;
        }
        // last element was not our left-neighbour so we need to call b method
        Pixel left = b.getLeft(p);
        neighbours.add(left);
        last = p;
    }
    // add all new neigbours
    pixels.addAll(neighbours);
}

This should allow you to save this memory which is allocated for duplicated Pixel objects.这应该允许您保存分配给重复Pixel对象的 memory。

I can see here few concerns regarding object oriented programming.我可以在这里看到一些关于 object 面向编程的担忧。

  1. Encapsulation violation: When you call function of B from A which operates on A's data (which you are avoiding by not sending HashMap), it violates encapsulation (If there is a reason, its acceptable though).封装违规:当您从 A 调用 B 的 function 对 A 的数据进行操作时(您通过不发送 HashMap 来避免这种情况),它违反了封装(如果有原因,尽管它是可以接受的)。 Is it possible to move that function (operating on A's HashSet) to A?是否可以将 function(在 A 的 HashSet 上操作)移动到 A? This will protect A's state from getting exposed.这将保护 A 的 state 不被暴露。
  2. Proliferation of classes: There is a possibility that there will be large number of objects of Point type.类的扩散:有可能会有大量的Point类型的对象。 You can think of using Flyweight GOF design pattern, it will externalize the state of each point and will make it reusable.您可以考虑使用享元 GOF 设计模式,它将每个点的 state 外化并使其可重用。 and will reduce number substantially.并将大幅减少数量。
  3. Passing large collection of Points to method in B: If you can shift method from B to A, this point gets resolved.将大量点集合传递给 B 中的方法:如果您可以将方法从 B 转移到 A,则该点得到解决。 Anyway java will pass this collection by reference.无论如何 java 将通过引用传递此集合。 But in that case its open for modifications from external classes (need to take care of this aspect).但在这种情况下,它对外部类的修改开放(需要注意这方面)。
  4. Abstraction of type Point : If class Point has only state and no behavior, it will lead to violation of encapsulation. Point类型的抽象:如果 class Point 只有 state 而没有任何行为,则会导致违反封装。 Can you shift the method getNeighbour() in to Point?您可以将方法getNeighbour()转换为 Point 吗? as it will make Point immutable (which is essential).因为它将使 Point 不可变(这是必不可少的)。 Off course actual algorithm can be delegated to another class (if its independently varying responsibility and has hierarchy of algorithms, think of GOF Strategy pattern here).当然,实际算法可以委托给另一个 class (如果其独立变化的职责并且具有算法层次结构,请在此处考虑 GOF 策略模式)。
  5. Uniqueness of points in collection: which your set will take care with due care about appropriate Hash and logical equality for class Point.集合中点的唯一性:您的集合将适当注意适当的 Hash 和 class 点的逻辑相等性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM