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

Mas*_*mad 8 java unit-testing design-patterns dependency-injection class

Status:Fendy和Glen Best的答案同样被我接受和尊重,但既然可以接受并给予赏金,我选择Fendy的答案.

Scenario:

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

必须重用的代码可以是任何理智的东西(适当考虑静态和非静态上下文和方法制作技术).它可以是一个算法,一个DB方法做连接,操作,关闭.任何东西.

  1. 创建一些类MyMethods.class,并将所有这些方法放入其中.

    表1.A 制作方法 static并直接调用(由所有类和并发线程)MyMethods.someMethod();

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

  2. 使用https://en.wikipedia.org/wiki/Strategy_pattern中声明的策略模式(此处附带的代码).

  3. 使用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只需调用一两个方法可以多次

  2. 那是我的头脑,解释那个和/或任何优点/缺点

  3. 也没有用一个框架在上下文中对这个问题..多数民众赞成的方式在我的头上,做解释和或任何优势/劣势

  4. 等待任何其他策略或建议,如果有的话.

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 );
    }
}
Run Code Online (Sandbox Code Playgroud)

Fen*_*ndy 8

你的问题实际上有两个含义.

必须在许多课程中多次重复使用

它可以是设计模式(可重用组件)或内存开销(类实例化)的上下文.从两个不同的角度谈话:

内存成本(我对此没什么经验,但让我分享一下我的经验)

这部分实际上只涵盖了2种实例化.

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

  • 渴望实例化,意味着在应用程序启动时将实例化所有类
  • 一次实例化

非静态

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

简而言之,如果类很多,静态将花费很高,如果请求很高,则静态将花费很高(例如,在for循环内).但它不应该使你的应用程序繁重.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
}
Run Code Online (Sandbox Code Playgroud)

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

// get data
if(request.IsDraft){
    draftRequestHandler.Modify(request);
}
else{
    publishedRequestHandler.Modify(request);
}
Run Code Online (Sandbox Code Playgroud)

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

单一责任原则

恕我直言,如果遵循这个原则是最有利的.优点是:

  1. 在版本控制中,更改清楚哪个类已被修改以及为什么
  2. 在DI中,可以连接几个较小的类,从而在使用和单元测试中创建灵活性
  3. 增加模块化,低耦合和高内聚力

TDD(测试驱动开发)

此设计不保证您的代码没有错误.考虑到在设计阶段和分层工作中花费时间,它具有以下好处:

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

一些有用的来源

服务定位器反模式

使用Decorator进行交叉关注

我的2美分:

使用界面的好处(也适用于继承的组合)

自上而下设计/ DI设计

最后的想法

这些设计和策略不是决定您的应用程序结构的关键.它仍然是决定它的建筑师.我更喜欢遵循一些原则,如SOLID,KISS和GRASP,而不是决定什么是最好的结构.据说依赖注入遵循这些原则中的大部分,但过多的抽象和不正确的组件设计将导致与单例模式的误用相同.