Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/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
Java 在实体生命周期的某个时间点更改其类型_Java_Design Patterns_Oop - Fatal编程技术网

Java 在实体生命周期的某个时间点更改其类型

Java 在实体生命周期的某个时间点更改其类型,java,design-patterns,oop,Java,Design Patterns,Oop,我有以下层次结构:Party是一个基类,由Person和Corporation扩展。 我需要在实体生命的某个时刻更改其对象类,我不知道最好的方法是什么 我在模拟金融世界,所以我认为一方可以拥有一家公司的股份,而只有公司才能拥有股东。大概是这样的: class Party { public Set getShares(); } class Corporation extends Party { public Set getShareholders(); public vo

我有以下层次结构:Party是一个基类,由Person和Corporation扩展。 我需要在实体生命的某个时刻更改其对象类,我不知道最好的方法是什么

我在模拟金融世界,所以我认为一方可以拥有一家公司的股份,而只有公司才能拥有股东。大概是这样的:

class Party {
    public Set getShares();
}

class Corporation extends Party {
    public Set getShareholders();
    public void setShareholders(Party ss);

}

class Person extends Party {
    ... (some method still unknown)
}
我构建从源读取数据的对象,可能一开始我只知道一方的名称,但不知道它是个人还是公司。 但是我需要创建一个对象,所以我创建了一个通用的Party。在那之后,我可能会了解更多的信息,因此我的政党是一家公司。因此,我需要将表示该实体的类从Party更改为Corporation。 到目前为止,我的解决方案是构建一个新对象,将旧数据复制到其中。 但我对它并不满意,我想知道实现我想要实现的目标的最佳方式、模式或其他方式是什么

我想是的,但我认为它最适合其他情况


一般来说,我不想改变对象的类。我想要的是有一些机制使客户机类遵守不同类型的契约。也就是说,我不希望一个类能够在一个人身上调用setShareholders,我如何实现这一点并不重要,我的意思是,除了使用类Person之外,实体是个人这一事实可能可以用其他方式表示。

我相信,没有其他方式。键入“new”后,您不能再进入类层次结构。你只能上去
我认为,出于显而易见的原因,向上投射是非常合乎逻辑的。然而,在Java(以及我所知道的每种语言)中,对象的向上转换只能通过向上转换引用而不是底层对象来完成。据我所知,向上投射底层对象是不可能的。
至于底层对象的向下转换,这也是不可能的。这可能与语言的一般设计有关,更重要的是,与内存分配问题有关。我会解释的。
假设类
Base
可以有最大4MB的RAM,而类
派生的
-7MB

因此,您的内存看起来是这样的(1个符号=1 Mb):
baseotherderived
。假设您告诉系统将第二个基类转换为派生类。系统可以这样做:
BASEDERIVEDERDERIVED
。正如您所看到的,对象“OTHER”以这种方式损坏。系统也可以这样做:
BASEDERIVEDOTHERDERIVED
。但在这种情况下,它必须移动其他对象和派生对象的地址,这是昂贵的,甚至可能是危险的和困难的,特别是当RAM中有两个以上的对象时。因此,首选的解决方案是:
BASE\uuuuuuuu otherderivedDerivedDerived
,其中
\uuuuuuuuuuuuuu
是可用空间,这类似于释放内存和分配新对象。

我有一个解决方案。这不漂亮,但你的问题也不是:

定义一个新类Translator。给出将一个人转换为公司的翻译器操作,反之亦然。当你需要在两者之间进行转换时,把令人讨厌的逻辑放在翻译器中。至少所有这些逻辑都将被隔离并可以测试

你的问题之所以如此困难,是因为你需要知道你的建筑是什么,才能建造它。尤其是构建器模式,由于这个原因而失败

另一种选择可能是使用。当你进一步了解你的团队拥有什么样的属性时,黑板的观察者可以尝试确定它是一个人还是一部分人


或者,您可以完全重新评估您的设计,并尝试从一个新的角度出发。

您不能在创建
java.lang.Object
之后更改它的类。您试图解决的问题可能很难解决,例如JavaScript实现的问题。然而,您正在用Java解决这个问题,这需要一些额外的工作

我只会保持党的阶级,并使它变得更聪明,以便能够处理其潜在类型之间的差异:个人和公司。以下代码段决不是一个完整的解决方案,只是为了说明该方法:

class Party {
    PartyKind kind;
    Map<String, Property<?>> properties;

    public Property getProperty(String name) {
        return properties.get(name);
    }
}

class Property<T> {
    T value;
}

enum PartyKind {
    PERSON,
    CORPORATION
}
班级聚会{
党羽类;
地图
一般来说,我不想真正改变对象的类。我想要的是有一些机制使客户端类遵守不同类型的契约。也就是说,我不希望一个类能够对一个人调用setShareholders,我如何实现这一点并不重要,我的意思是,可能一个实体是除了使用类Person,Person还可以用其他方式表示

最后一段让我想到a可以满足你的需要。如果你有一个“实体”E,它“是一个人,可以用除类人以外的其他方式来表示”。代理可以包装你的实体E,并“实现”/仅显示所需的接口
Person
(同时隐藏任何其他实现的接口或关于E的实现细节)

编辑:由于OP发现答案很有用,我添加了一个实用程序类和演示代码:

一些代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Utilities to support using dynamic proxies
 */
public class DynamicProxy {

    /**
     * An invocation handler that passes calls to its delegate. This class
     * could be subclassed to provide dynamic method invocation handling
     * while still being able to fall back to the delegate object's methods.
     *
     * @see InvocationHandler
     */
    public static class DelegatingInvocationHandler
    implements InvocationHandler {

        /** The object this proxy is wrapping */
        private final Object delegate;

        /**
         * Creates a delegate invocation handler around an object
         *
         * @param object
         *            The object to wrap
         */
        public DelegatingInvocationHandler(final Object delegate) {
            this.delegate = delegate;
        }

        /* (non-Javadoc)
         *
         * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
         * java.lang.reflect.Method, java.lang.Object[])
         */
        @Override
        public Object invoke(final Object proxy, final Method m,
                final Object[] args) throws Throwable {
            Object result;

            try {
                result = m.invoke(delegate, args);
            } catch (final InvocationTargetException e) {
                throw e.getTargetException();
            } catch (final Exception e) {
                throw new RuntimeException("unexpected invocation exception: "
                        + e.getMessage());
            }

            return result;
        }
    }

    /**
     * Create a dynamic proxy that implements only a specified subset of the
     * original object's implemented interfaces. The proxy allows you to
     * essentially hide the other interfaces implemented by the original
     * object.
     *
     * @param delegate
     *            the object that the proxy "proxies" for (a.k.a. the delegate
     *            that handles the calls the proxy "allows" through)
     * @param requiredInterface
     *            one of the interfaces of the delegate that the proxy exposes
     * @param moreInterfaces
     *            any additional interfaces of the delegate to expose
     * @return the proxy
     *             a proxy for the delegate that can be cast to any of the
     *             specified interfaces
     */
    public static <T> T createSelectiveProxy(final T delegate,
            final Class<T> requiredInterface,
            final Class<?>... moreInterfaces) {
        if (delegate == null) {
            throw new IllegalArgumentException(
                    "The delegate object cannot be null");
        }

        return createProxy(new DelegatingInvocationHandler(delegate),
                requiredInterface, moreInterfaces);
    }

    /**
     * Creates a proxy using the specified invocation handler.
     *
     * @param object
     *            the implementing object that proxy wraps
     * @param invocationHandler
     *            the interfaces
     * @param moreInterfaces
     *            the interfaces
     * @return the object
     */
    @SuppressWarnings("unchecked")
    public static <T> T createProxy(final InvocationHandler invocationHandler,
            final Class<T> requiredInterface,
            final Class<?>... moreInterfaces) {
        if (invocationHandler == null) {
            throw new IllegalArgumentException(
                    "The invocation handler cannot be null");
        }

        final int size = (moreInterfaces != null ? moreInterfaces.length : 0);
        final Class<?>[] interfaces = new Class<?>[size + 1];
        interfaces[0] = requiredInterface;
        System.arraycopy(moreInterfaces, 0, interfaces, 1, moreInterfaces.length);

        return (T) Proxy.newProxyInstance(invocationHandler.getClass()
                .getClassLoader(), interfaces, invocationHandler);
    }
}
运行:

这是一种实现目标的简单技术,尽管在最初的Party实例中最多只有一个decorator

我对Java的类不太熟悉,但维基百科的链接说这是可行的

一般来说,我不想改变对象的类

我不认为不改变对象的类别,你就能够做到这一点。无论如何,我只是给你一个替代方案。这不是你问题的答案,但它可能会给你一些想法

抽象党类:

abstract class Party {
    protected String nameOfParty;
    private Set<String> shares=new HashSet<String>();
    public Party(String name) {
        nameOfParty=name;
    }
    public Set<String> getShares(){
        return shares;
    }
    public void addShare(Party corp) {
         shares.add(((Corp)corp).nameOfParty);//only add corporation's share.
    }
}
测试:

public class Corp extends Party {
    private Set<String> shareHolders = new HashSet<String>();

    public Corp(String name) {
        super(name);
    }

    public Corp(Party per) {
        super(per.nameOfParty);
    }

    public Set<String> getShareholders() {
        return shareHolders;
    }

    public void addShareholder(Party shareHolder) {
        this.shareHolders.add(shareHolder.nameOfParty);
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Name Of Corp : ").append(nameOfParty);
        sb.append("\nShare's: ").append(this.getShares());
        sb.append("\nShare Holder's : ").append(shareHolders);
        return sb.toString();
    }

}
public class Person extends Party {

    public Person(String name) {
        super(name);
    }

    public Person(Party name) {
        super(name.nameOfParty);
    }

    public void unknowMethod() {

    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Name Of Person : ").append(nameOfParty);
        sb.append("\nShare's: ").append(this.getShares());
        return sb.toString();
    }

}
public class Test {
    public static void main(String[] args) {
    /*
     * Initially consider all party's to be person's 
     * or create party with anonymous class if party information
     * is not available at that time of creation.
     */
        Party google = new Party("Google") {}; //Party with anonymous class
        Party yahoo = new Person("Yahoo");
        Party george = new Person("George");
        Party ali = new Person("Ali");
        Set<Party> list = new HashSet<Party>();

        list.add(google);
        list.add(yahoo);
        list.add(george);
        list.add(ali);
        // later came to know that google and yahoo are corporation's
        google = changeToCorp(list, google);
        yahoo = changeToCorp(list, yahoo);

        for (Party pty : list) {
            if (pty instanceof Person) {
                Person p = (Person) pty;
                p.unknowMethod();// access method's of person
                p.addShare(yahoo);
                p.addShare(google);
                /*p.addShare(ali); 
                  will throw exception since ali is a person and cannot be added as share*/
                System.out.println("\n" + pty);
            }
            if (pty instanceof Corp) {
                Corp c = (Corp) pty;
                c.addShareholder(george);// access method's of corp
                c.addShareholder(yahoo);
                c.addShare(google);
                c.addShareholder(ali);// share holder's can be either a person or a corporation
                System.out.println("\n" + pty);
            }
        }

    }

    static Corp changeToCorp(Set<Party> se, Party per) {
        se.remove(per);
        Corp p = new Corp(per);
        se.add(p);
        return p;
    }

}
公共类测试{
公共静态void main(字符串[]args){
/*
*最初考虑所有党的人
*或者创建匿名类的参与方,如果
public class Person extends Party {

    public Person(String name) {
        super(name);
    }

    public Person(Party name) {
        super(name.nameOfParty);
    }

    public void unknowMethod() {

    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Name Of Person : ").append(nameOfParty);
        sb.append("\nShare's: ").append(this.getShares());
        return sb.toString();
    }

}
public class Test {
    public static void main(String[] args) {
    /*
     * Initially consider all party's to be person's 
     * or create party with anonymous class if party information
     * is not available at that time of creation.
     */
        Party google = new Party("Google") {}; //Party with anonymous class
        Party yahoo = new Person("Yahoo");
        Party george = new Person("George");
        Party ali = new Person("Ali");
        Set<Party> list = new HashSet<Party>();

        list.add(google);
        list.add(yahoo);
        list.add(george);
        list.add(ali);
        // later came to know that google and yahoo are corporation's
        google = changeToCorp(list, google);
        yahoo = changeToCorp(list, yahoo);

        for (Party pty : list) {
            if (pty instanceof Person) {
                Person p = (Person) pty;
                p.unknowMethod();// access method's of person
                p.addShare(yahoo);
                p.addShare(google);
                /*p.addShare(ali); 
                  will throw exception since ali is a person and cannot be added as share*/
                System.out.println("\n" + pty);
            }
            if (pty instanceof Corp) {
                Corp c = (Corp) pty;
                c.addShareholder(george);// access method's of corp
                c.addShareholder(yahoo);
                c.addShare(google);
                c.addShareholder(ali);// share holder's can be either a person or a corporation
                System.out.println("\n" + pty);
            }
        }

    }

    static Corp changeToCorp(Set<Party> se, Party per) {
        se.remove(per);
        Corp p = new Corp(per);
        se.add(p);
        return p;
    }

}