当前位置: 首页 > 面试题库 >

Methods.class与策略模式和依赖项注入中的代码重用

穆理
2023-03-14
问题内容

Status: Fendy和Glen Best的答案 同样 被我 接受
和尊重,但由于可以接受并给予赏金,因此我选择Fendy的答案。

Scenario:

如果我有 一些代码被多次重复使用许多类 (很少有轻微参数改变是显而易见的)和并发线程,哪种方法去?

必须重用的代码可以是任何理智的东西(在考虑了静态和非静态上下文以及方法制作技术的前提下)。它可以是一种算法,一种执行connect,operate,close的DB方法。什么都可以

  1. 使类 变得 很像,MyMethods.class然后 将所有这些方法放入其中

1.a. 制作 方法 static和呼叫(在各个阶层和并发线程)直接作为MyMethods.someMethod();

1.b. 制作 方法 non-static和当时打电话给他们, instantiate 全班通过MyMethods mm = MyMethods(); mm.someMethod();

  1. 使用https://en.wikipedia.org/wiki/Strategy_pattern中所述的 策略模式 (代码随附于此)。

  2. 使用https://en.wikipedia.org/wiki/Dependency_injection#Java中所述的 依赖项注入

Problems:

  1. 有人会说,使用这种方法将 无法进行* 单元测试 http://en.wikipedia.org/wiki/Unit_testing , 在换出 后者时会 遇到麻烦 。如果你想测试你的类,并使用一个 模拟版本 中的 依赖 ***

1.a. 并发 调用或多个类是否会有问题?特别JDBC static methods是一个例子?

1.b. 我认为这将导致过多的 内存负载, 因为仅调用一个或两个方法 需要花费instanticated很多时间。

  1. 多数民众赞成在我头上,请解释一下和/或任何优点/缺点

  2. 也没有用一个框架 在上下文中对这个问题..在我头上那顺便说一下,解释和或任何优势/劣势

  3. 等待任何其他策略或建议(如果有)。

Request: 请仅在有经验的情况下回答,并深刻理解其含义,并能以您的回答全面帮助我和整个社区!

Code:

/** The classes that implement a concrete strategy should implement this.
* The Context class uses this to call the concrete strategy. */
interface Strategy {
    int execute(int a, int b); 
}

/** Implements the algorithm using the strategy interface */
class Add implements Strategy {
    public int execute(int a, int b) {
        System.out.println("Called Add's execute()");
        return a + b;  // Do an addition with a and b
    }
}

class Subtract implements Strategy {
    public int execute(int a, int b) {
        System.out.println("Called Subtract's execute()");
        return a - b;  // Do a subtraction with a and b
    }
}

class Multiply implements Strategy {
    public int execute(int a, int b) {
        System.out.println("Called Multiply's execute()");
        return a * b;   // Do a multiplication with a and b
    }    
}

// Configured with a ConcreteStrategy object and maintains
// a reference to a Strategy object 
class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public int executeStrategy(int a, int b) {
        return this.strategy.execute(a, b);
    }
}

/** Tests the pattern */
class StrategyExample {
    public static void main(String[] args) {
        Context context;

        // Three contexts following different strategies
        context = new Context(new Add());
        int resultA = context.executeStrategy(3,4);

        context = new Context(new Subtract());
        int resultB = context.executeStrategy(3,4);

        context = new Context(new Multiply());
        int resultC = context.executeStrategy(3,4);

        System.out.println("Result A : " + resultA );
        System.out.println("Result B : " + resultB );
        System.out.println("Result C : " + resultC );
    }
}

问题答案:

您的问题实际上有两个含义。

必须在许多类中多次重用

它可以是设计模式(可重用组件)或内存成本(类实例化)的上下文。从两种不同的角度谈:

内存成本 (我对此没有多少经验,但让我分享经验)

本节实际上仅涵盖2种实例化。

首先是静态的(或合成根中的DI实例化)

  • 急切的实例化,意味着所有类将在应用程序启动时实例化
  • 仅一次实例化

非静态

  • 延迟实例化,意味着类仅在需要时实例化
  • 每次使用一次实例化

简而言之,如果类很多,那么静态将花费很高,而如果请求很高(例如,在循环内部),则非静态将花费很高。但这不应该使您的应用程序繁重。尽管在Java /
csharp中,大多数操作都是创建对象。

类可重用性

1-巨型单片代码(一个神职人员几乎可以完成所有工作)

优点:

  1. 易于搜索代码(尽管还是要视情况而定),您知道每个逻辑都在那里,因此您只需要查看该大类即可
  2. 如果它是静态的,则可以在任何地方调用它而不必担心实例化

缺点:

  1. 对一种方法的任何修改都会在其他地方带来错误的风险
  2. 违反SRP,意味着可以出于各种原因(不仅是一种原因)更改此类
  3. 特别是在版本控制中,如果修改发生在单独的分支中,则很难合并,从而导致同步代码的工作量

1a /静态类/单例模式

优点:

  1. 易于使用
  2. 可以在任何地方使用(只需参考和调用即可完成)
  3. 不需要实例化对象

缺点:

  1. 难以进行单元测试(很难模拟,并且在以后的时间中,您会发现准备测试环境需要花费时间。尤其是对于数据而言)
  2. 如果是有状态的(有状态),则在调试期间很难确定当前状态。而且,很难确定哪个功能可以改变状态,可以随时随地改变
  3. 倾向于有很多参数(可能在5-11左右)

2策略模式

实际上,它的设计与3或相同composition over inheritance

3依赖注入

优点:

  • 易于模拟和单元测试
  • Must be stateless。如果类是无状态的,则调试和单元测试更加容易
  • 支持重构

缺点:

  • 对于那些不熟悉接口的人来说很难调试(每次您重定向到方法时,它都会转到接口的方法)
  • 创建将导致映射的分层

状态/无状态

我认为状态在您的应用程序设计中起着重要的规则。通常,开发人员尝试避免在业务逻辑代码中包含状态,例如:

// get data
if(request.IsDraft){
  // step 1
  // step 2
}
else{
  // step 1
  // step 3
}

开发人员倾向于将逻辑放在其他stateless类中,或者至少将诸如以下方法:

// get data
if(request.IsDraft){
    draftRequestHandler.Modify(request);
}
else{
    publishedRequestHandler.Modify(request);
}

它将提供更好的可读性,并且更易于修改和单元测试。也有一种设计模式state pattern or hierarchial state machine pattern,特别是处理这样的情况。

单一责任原则

恕我直言,如果遵循这一原则,则将带来最大的好处。优点是:

  1. 在版本控制中,所做的更改清楚地表明了修改了哪个类以及为什么
  2. 在DI中,可以连接几个较小的类,从而在使用和单元测试方面都具有灵活性
  3. 增加模块化,低耦合和高内聚性

TDD(测试驱动开发)

这种设计不能保证您的代码没有错误。考虑到在设计阶段花费时间和分层工作,它具有以下优点:

  1. 易于模拟对象以进行单元测试
  2. 由于单元测试和模块化,更易于重构
  3. 易于维护/扩展

一些有用的资源

服务定位器反模式

使用Decorator处理横切关注点

最后的想法

这些设计和策略不是决定您的应用程序结构的关键。仍然由建筑师来决定。我宁愿遵循诸如SOLID,KISS和GRASP之类的原则,而不是确定最佳的结构。据说依赖注入遵循了大多数原则,但是过多的抽象和不正确的组件设计将导致滥用单例模式。



 类似资料:
  • 问题内容: 当前在app.js中,我有以下路线: 如您所见,我正在尝试注入Path依赖项。尽管我收到一条错误消息,说找不到该提供程序。我认为这是因为配置模块提供程序首先执行。以下是“ services.js”中我的路径提供程序定义 我怎样才能将此提供程序注入配置模块? 问题答案: 在中,只能使用提供程序(例如)。在你只能使用服务(如实例)。您有一家工厂,而不是供应商。请参阅具有以下三种创建方式的代

  • 本文向大家介绍依赖注入和工厂模式之间的区别。,包括了依赖注入和工厂模式之间的区别。的使用技巧和注意事项,需要的朋友参考一下 工厂注入和依赖注入都是设计模式,可用于增强软件组件之间的松散耦合能力。  工厂设计模式用于创建对象。但是,对象的注入和生命周期管理应由应用程序内的程序员处理。无法在单个位置配置所有内容。因此,程序员需要在任何需要的地方调用对象创建逻辑,这最终会阻碍松散的耦合能力。 在DI设计

  • 问题内容: 给出以下代码: 以 主要 方式完成的组件连接是否正确,将依赖关系连接在一起?看来我在代码中有点用完了。有没有比这更好的通用模式了?还是我想得太多? 问题答案: 是的,facebookgo注入库允许您接受注入的成员,并将为您连接图表。 代码:https://github.com/facebookgo/inject 文档:https : //godoc.org/github.com/fac

  • 我有以下课程: 这只是其中一个例子,我有一些类似的其他类,我将它们作为依赖注入到其他类中。但是它使我的SchemaFetcher类像一个单例,我不断地向它的每一个方法传递模式定义。这似乎是非常程序化的,我想实际上使模式定义成为数据库模式获取类的实例变量,但在这种情况下,我将无法将模式获取对象注入到我的验证器类中,相反,我应该这样做 但这使我与fetcher紧密耦合,这就是为什么我想首先使用依赖注入

  • 让我们创建一个名为的新模块,并在那里定义CounterService。 app/shared/shared.module.ts 现在我们将引入 SharedModule 到AppModule 和中。 app/lazy/lazy.module.ts 使用此配置,两个模块的组件都可以访问CounterService。 我们将以完全相同的方式在EagerComponent和LazyComponent中使

  • 我正在寻找一种优雅的方式,在标准spring服务中定义字段 如果没有龙目,我们的服务如下: 现在,我们的团队只想使用lombok构造函数(这样我们就可以轻松地添加其他服务)。上面的服务现在看起来是这样的: 如何解决这些问题(在源代码注释中提到)? 我在很多项目中都看到了这个“问题”。我上面提到的变体是我看到的唯一解决方案。当增加字段数量时,这两种解决方案都变得更加丑陋。