热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何改变设计以便实体不使用注射?

如何解决《如何改变设计以便实体不使用注射?》经验,为你挑选了1个好方法。

我已经阅读并开始意识到实体(数据对象 - 用于JPA或序列化)注入其中是一个坏主意.这是我目前的设计(所有适当的字段都有getter和setter,serialVersionUID为简洁起见我放弃了).

这是父对象,它是实体组合图的头部.这是我序列化的对象.

public class State implements Serializable {

    List cars = new ArrayList<>();

    List planes = new ArrayList<>();

   // other objects similar to AbstractPlane as shown below
}

AbstractPlane 它的子类只是没有注入的简单类:

public abstract class AbstractPlane implements Serializable {
    long serialNumber;
}

public class PropellorPlane extends AbstractPlane {
    int propellors;
}

public class EnginePlane extends AbstractPlane {
    List engines = new ArrayList<>(); // Engine is another pojo
}

// etc.

相比之下,每种具体类型的汽车都需要一个拥有某些行为的经理以及一些特定形式的数据:

public abstract class AbstractCar implements Serializable {
    long serialNumber;

    abstract CarData getData();

    abstract void operate(int condition);

    abstract class CarData {
        String type;
        int year;
    }
}

public class Car1 extends AbstractCar {

    @Inject
    Car1Manager manager;

    Car1Data data = new Car1Data(); // (getter exists per superclass requirement)

    void operate(int i) { // logic looks weird but makes the example
        if (i <0)
            return manager.operate(data);
        else if (i > 1)
            return manager.operate(data, i);
    }

    class Car1Data extends CarData {
        int property1;

        {
            type = "car1";
            year = 1;
        }
    }
}

public class Car2 extends AbstractCar {

    @Inject
    Car2Manager manager;

    Car2Data data = new Car2Data();

    void operate(int i) {
        if (i <31)
            return manager.operate(data);
    }

    class Car2Data extends CarData {
        char property2;

        {
            type = "car2";
            year = 12;
        }
    }
}

// etc.

CarxManager@Stateless,其上的数据(匹配执行操作豆CarxData给它们).他们自己进一步使用注射许多其他豆类,它们都是AbstractCarManager.有O(100)车型和匹配经理.

序列化时的问题State是序列化抽象汽车列表与子类中的注入不相符.我正在寻找一种将注射与数据保存过程分离的设计.

我以前的相关问题:如何序列化注入的bean?和我怎么能告诉CDI容器"激活"豆?



1> Justin.Cooke..:

您可以使用存储库模式.将业务逻辑放入服务中,并将存储库(将抽象机制抽象化)和管理器注入其中.存储库隐藏了业务服务中的持久性实现细节,而实体只是简单的POJO.

它看起来像下面的Foo是实体Bar的id:

public class CarService {

    @Inject
    CarRepository carRepository;

    @Inject
    CarManager manager;

    piblic void operate(final Foo foo) {

        Bar myBar = carRepository.retrieve(foo);
        manager.doSomethingTo(myBar);
        carRepository.persist(myBar);

    }
}

另请参阅:存储库模式逐步说明,http://deviq.com/repository-pattern/.一些框架(如Spring Data JPA或deltaspike)已经为您实现了存储库模式,您需要做的就是提供如下所示的接口,并在后台生成实现:

@Repository
public interface CarRepository extends EntityRepository {}

标记回答您的更多细节请求我将提供一个改进的解决方案,因为问题中的示例对我来说真的没有意义,并展示了一些导致有问题的软件的反模式.

找到问题的一个很好的解决方案涉及很多不同的考虑因素,其中很多都是非常大的主题,有许多关于它们的书籍,但我会尽力说明我的想法,以解决上述问题.

并且道歉,因为我毫不怀疑你知道其中许多,但为了清楚起见,我将假设有限的知识.

解决这个问题的第一步不是关于代码,而是关于模型本身,模型驱动开发在Eric Evan的书中被广泛涵盖,如下面的评论所述.该模型应该驱动实现,并且还应该作为分层体系结构的一部分存在于其自己的层上,并且由实体,值对象和工厂组成.

模型驱动开发

在问题中给出的模型中,我们有一个叫做State的东西,它包含AbstractPlanesAbstractCars.您正在使用JPA来保持状态,这实际上是您的飞机和汽车的总和.首先在软件中调用任何状态是一种难闻的气味,因为几乎所有东西都具有某种状态,但是调用我们在这里所拥有的东西是一种聚合状态甚至没有意义.

一个国家与另一个国家有何不同?是一个汽车零件国家和不同的另一部分国家还是所有的飞机和汽车属于一个实例的情况下国家.在这种情况下,飞机和汽车之间的关系是什么?飞机清单和汽车清单如何与单个国家实体有任何关系?

好吧,如果State实际上是一个机场,我们对当前有多少架飞机和汽车感兴趣,那么这可能是正确的型号.如果国家是一个机场,它将有一个名称或身份,如机场代码,但它没有,所以......

...在这种情况下,似乎State是一个对象,它被用作方便我们访问对象模型的对象.因此,我们通过实施考虑有效地推动我们的模型,当我们应该反过来这样做并从我们的模型推动我们的实现.

CarData这样的术语出于同样的原因也存在问题,创建Car实体然后单独的对象来存储其数据是混乱和混乱的.

如果不能正确地获得模型,则会导致最好混淆的软件,最糟糕的是完全不起作用的软件.这是IT项目失败的最大原因之一,项目越大,这项工作就越难以实现.


修订模型

所以从模型中我了解到我们有汽车,我们有飞机,其实例都是具有自己身份的独特实体.在我看来,它们是分开的东西,因此坚持将它们包含在某个聚合实体中没有意义.

public class Plane {...}

public class Car {...}

另一个考虑因素是在模型中使用抽象类,通常我们希望应用有利于组合而不是继承原则,因为继承可能导致隐藏行为,并且它可能使模型难以阅读.例如,为什么我们有ProperllerPlaneEnginePlane?当然,螺旋桨只是一种发动机?我大大简化了模型:

public class Plane implements Serializable {

    @Id
    private String name;
    private String model;
    private List engines;

Plane是具有自己的属性和标识的实体.为了存储属性,不需要在现实世界中代表任何东西的其他类.引擎对象当前是一个枚举,表示平面中使用的引擎类型:

public enum Engine {
    PROPELLER, JET
}

如果引擎本身需要身份,就像在现实生活中引擎序列号和事物被跟踪一样,那么我们会将其更改为对象.但是我们可能不希望允许访问它,除非通过Plane实体实例,在这种情况下Plane将被称为聚合根 - 这是一个高级主题,我会推荐Evan的书来获取有关聚合的更多详细信息.

Car实体也是如此.

@Entity
public class Car implements Serializable{

    @Id
    private String registration;
    private String type;
    private int year;

以上是您在模型基础上提供的所需内容.然后我创建了几个工厂类来处理这些实体的实例创建:

public class CarFactory {

    public Car makePosrche(final String registrationNumber) {
        Car porsche = new Car();
        porsche.setRegistration(registrationNumber);
        porsche.setType("Posrshe");
        porsche.setYear(1986);
        return porsche;
    }
}

public class PlaneFactory {

    public Plane makeSevenFourSeven(final String name) {
        Plane sevenFourSeven = new Plane();
        List engines = new ArrayList();
        engines.add(JET);
        engines.add(JET);
        engines.add(JET);
        engines.add(JET);
        sevenFourSeven.setEngines(engines);
        sevenFourSeven.setName(name);
        return sevenFourSeven;
    }

    public Plane makeSpitFire(final String name) {
        Plane spitFire = new Plane();
        List engines = new ArrayList();
        engines.add(PROPELLER);
        spitFire.setEngines(engines);
        spitFire.setModel("Spitfire");
        spitFire.setName(name);
        return spitFire;
    }
}

我们在这里所做的是根据单一责任原则将问题分开,每个班级应该只做一件事.


现在我们有了一个模型,我们需要知道如何与它进行交互.在这种情况下,我们很可能如果使用JPA将汽车保持在一个名为Car和飞机的表中.我们将通过存储库,CarRepository和PlaneRespository提供对这些持久化实体的访问.

然后,您可以创建名为services的类,这些类会注入存储库(以及您需要的任何其他内容),以便对汽车和飞机的实例执行CRUD(创建读取更新删除)操作,此外,您可以将业务逻辑应用于这些.比如你的方法:

void operate(int i) {..}

通过以这种方式构造代码,您可以将模型(实体和值对象)与它们如何持久存储(存储库)从您对其进行操作的服务(如您的问题中所述)进行分离:

我正在寻找一种将注射与数据保存过程分离的设计.


推荐阅读
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • 标题: ... [详细]
  • 集合的遍历方式及其局限性
    本文介绍了Java中集合的遍历方式,重点介绍了for-each语句的用法和优势。同时指出了for-each语句无法引用数组或集合的索引的局限性。通过示例代码展示了for-each语句的使用方法,并提供了改写为for语句版本的方法。 ... [详细]
  • 在springmvc框架中,前台ajax调用方法,对图片批量下载,如何弹出提示保存位置选框?Controller方法 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 本文介绍了Java中Hashtable的clear()方法,该方法用于清除和移除指定Hashtable中的所有键。通过示例程序演示了clear()方法的使用。 ... [详细]
  • Week04面向对象设计与继承学习总结及作业要求
    本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ... [详细]
author-avatar
手机用户2702937407_195
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有