在Java

时间:2016-02-22 20:12:47

标签: java design-patterns enums

我的代码库中有2个构建器,可以像这样访问:

return new Developer.Builder("John", "Doe").age(30).build();
return new Manager.Builder("Eve", "Page").age(40).build();

我希望通过封装在枚举中来简化API:

return Google.Developer.Builder("John", "Doe").age(30).build();
return Google.Manager.Builder("Eve", "Page").age(40).build();

我的目标是简化

的过程
  1. 将公司名称从Google更改为Microsoft
  2. 如果添加了新角色(除了开发人员和经理),我的代码用户可以在一个地方了解它。
  3. 我想到的唯一选择是将公司名称作为枚举 - 但之后我将无法实现构建器模式。

3 个答案:

答案 0 :(得分:2)

您可以添加代表公司的界面

interface Company{
}

并有一个众所周知的公司,

enum Companies implements Company{
 GOOGLE,
 MICROSOFT,
 ...
}

现在,在您的构建器中,您可以添加一个方法,该方法需要Company而不是enum

Builder company(Company company){
  addCompany(company);
  return this;
}

像这样流利地构建它

Developer.Builder("John", "Doe").company(Companies.GOOGLE).age(30).build();

现在公司可以是常量,也可以是从db(任何实现Company的东西)加载的东西。无论哪种方式都是类型安全的。

答案 1 :(得分:2)

您可以创建类似于您描述的API:

var getPeople = function() {    
  return $http.get('/getnames').then(function(response) {
    return response.data;
  });    
};


getPeople().then(function(people) {
  var promises = [];

  people.forEach(function(person) {
    // push new requests to promise array
    promises.push(getSkills(person));
    promises.push(getCount(person))

  });
  // when all promises resolved return `people`
  return $q.all(promises).then(function() {
     // return `people` to next `then()`
    return people;
  });
}).then(function(people) {
  console.log(people);
  $scope.people = people;

}).catch(function(){
   // do something if anything gets rejected
});

function getCount(person) {
  var urlc = '/getcountbyname/' + person.name;    
  return $http.get(urlc).then(function(response) {
    person.count = response.data
  });

}

function getSkills(person) {
  var urls = '/getskillsbyname/' + person.name;
  return $http.get(urls).then(function(response) {
    person.skills = response.data
  });

}

现在你可以写

enum Google {
    Developer, Manager;

    public Builder builder(String name) {
        return new Builder(this, name);
    }

    public static class Builder {
        public Builder(Google role, String name) { ... }
        public Builder age(int age) { ... }
        public Employee build() { ... }
    }
}

我不明白这一切是什么意思。建筑商是否以某种方式依赖于公司和角色?

如果没有,您可以将Builder定义为一个单独的类,并使用界面来标记公司中代表角色的内容,类似于Sleiman的答案。 如果在您的应用程序中有意义,您甚至可以将Employee e = Google.Developer.builder("John").age(30).build(); 类与公司进行参数化...

Employee

你仍然可以写

interface CompanyRole { /* just a marker */ }

enum Google implements CompanyRole { 
    ...
    Employee.Builder<Google> builder(String name) {
        return new Employee.Builder<>(this, name);
    }
}

class Employee<T extends CompanyRole> { 
    ... 

    static class Builder<T extends CompanyRole> {
        EmployeeBuilder(T role, String name) { ... }
        Employee<T> build() { ... }
    }
}

答案 2 :(得分:1)

评分

return Google.Developer.DevBuilder("John", "Doe").age(30).build();

这没有任何意义。仔细看看,上面的调用会导致类Google,其中包含内部类Developer。该类定义了一个名为DevBuilder静态方法,它带有2个参数,名字和姓氏,并返回Builder / DeveloperBuilder的实例。

这不是面向对象的可扩展方法。即使你给了我们很少的背景,我也认为公司是静态的对象,它们不会发生变化。参考您在评论中所做的示例 - 新公司比新CompressFormat更有可能。

此外,除了动态调用age(int)build()之外,不可能通过多态改变行为。

动态方法

下面是一个更动态的方法的概念(当然应该添加机制,以确保公司只有一个对象,例如Company.byName("Google")等)。

public static void main(String[] args) {
    Company google = new Google();
    Manager manager = google.newManager();
}

static abstract class Company {
    public Manager newManager() {
        return new ManagerBuilder("Eve", "Page").age(40).build();
    }
}

static class Google extends Company {
}

您可以轻松添加新公司并更改经理(或任何其他员工)的​​创建方式,您也可以使用默认公司。

重构

通过更多的游戏,您可以通过创建两个基类来删除员工及其相应构建器的类中的样板代码

static abstract class Person<P extends Person<P>> {
    protected final String firstName;
    protected final String lastName;
    protected final int age;

    public <T extends AbstractBuilder<P, T>> Person(AbstractBuilder<P, T> builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
    }
}

static abstract class AbstractBuilder<P extends Person, T extends AbstractBuilder<P, T>> {
    protected final String firstName;
    protected final String lastName;
    protected int age;

    public AbstractBuilder(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    abstract T self();

    abstract P build();

    T age(int age) {
        this.age = age;
        return self();
    }
}

利用上述内容,创建一个类Manager及其Builder会产生以下代码

static class Manager extends Person<Manager> {
    public <T extends AbstractBuilder<Manager, T>> Manager(AbstractBuilder<Manager, T> builder) {
        super(builder);
    }
}

static class ManagerBuilder extends AbstractBuilder<Manager, ManagerBuilder> {
    public ManagerBuilder(String firstName, String lastName) {
        super(firstName, lastName);
    }

    @Override
    ManagerBuilder self() {
        return this;
    }

    @Override
    Manager build() {
        return new Manager(this);
    }
}

Manager及其Builder或任何其他员工可以使用更多字段进行扩展。