首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >我如何才能有一个行为丰富的领域实体,坚持开放-封闭原则?

我如何才能有一个行为丰富的领域实体,坚持开放-封闭原则?
EN

Stack Overflow用户
提问于 2012-09-04 01:44:18
回答 5查看 656关注 0票数 7

Open-Closed Principle指出:

软件实体(类、模块、功能等)应开放供扩展,但因修改而关闭。

我现在正在设计一个域,并且在我的领域实体中包含了相当多的行为。我使用域事件并将依赖项注入到方法中,因此确保我的实体不与外部影响相耦合。但是,在我看来,如果客户机以后想要更多的功能,我将不得不违反OCP并打开这些域实体来添加这些功能。一个行为丰富的领域实体如何与开放-封闭原则和谐相处?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-09-04 03:12:41

在设计类时,记住开闭原则(OCP)是很有用的,但让类立即“封闭以供修改”并不总是切实可行或可取的。我认为单责任原则(SRP)在实践中更有用--只要一个类只做一件事,就可以修改它,如果对这件事的要求发生变化。

此外,随着时间的推移,SRP会导致OCP;如果您发现自己经常更改一个类,则最终会重构它,以便将更改部分隔离到一个单独的类中,从而使原始类更加封闭。

票数 5
EN

Stack Overflow用户

发布于 2012-09-04 08:12:18

答案很简单:工厂方法和接口+组合。

打开扩展意味着使用新的子类添加新功能。

若要启用此功能,必须使用工厂来创建域对象。我通常使用我的存储库作为工厂。

如果您使用接口而不是具体代码编写代码,那么您可以轻松地添加新功能:

  • IUser
  • IManager : IUser (添加了一些管理器功能)
  • ISupervisor : IUser (添加管理器功能)

这些特性本身可以是小类,包括使用组合:

代码语言:javascript
运行
复制
public class ManagerSupervisor : User, IManager, ISupervior
(
    public ManagerSupervisor()
    {
        // used to work with the supervisor features.
        // without breaking Law Of Demeter
        _supervisor = new SuperVisorFeatures(this);

    }
)
票数 0
EN

Stack Overflow用户

发布于 2012-09-08 00:38:02

这是一个棘手的解释,没有一些具体的例子。我建议您阅读Robert的书“敏捷软件开发、原则、模式和实践”。这本书也是开放关闭原则的来源.

具有丰富行为的域对象不与开放关闭原则相冲突。如果他们没有行为,你就不能创造合理的延伸。应用开放关闭原则的关键是预测未来的变化,并创建新的接口来完成角色,并让它们承担单一的责任。

我将讲述一个在实际代码中应用开闭原则的故事。希望能帮上忙。

我有一个发件人类,在开始时发送消息:

代码语言:javascript
运行
复制
package com.thinkinginobjects;

public class MessageSender {

private Transport transport;

public void send(Message message) {
    byte[] bytes = message.toBytes();
    transport.sendBytes(bytes);
}
}

有一天,我被要求用10批邮件发送信息。一个简单的解决方案是:

包装com.thinkinginobjects;

公共类MessageSenderWithBatch {

代码语言:javascript
运行
复制
private static final int BATCH_SIZE = 10;

private Transport transport;

private List<Message> buffer = new ArrayList<Message>();

public void send(Message message) {
    buffer.add(message);
    if (buffer.size() == BATCH_SIZE) {
        for (Message each : buffer) {
            byte[] bytes = each.toBytes();
            transport.sendBytes(bytes);
        }
                    buffer.clear();
    }
}
}

然而,我的经验告诉我,这也许不是故事的结局。我预计人们会需要不同的方式来分批消息。因此,我创建了一个批处理策略,并让发件人使用它。注意到我在这里应用了开放关闭原则。如果我将来有一种新的批处理策略,我的代码是开放的(通过添加一个新的BatchStrategy),但是接近修改(通过不修改任何现有的代码)。然而,正如Robert在他的书中所指出的,当代码为某些类型的更改打开时,它也接近于其他类型的更改。如果将来有人想在发送完组件后通知组件,我的代码就不会为这种类型的更改打开。

代码语言:javascript
运行
复制
package com.thinkinginobjects;

public class MessageSenderWithStrategy {

private Transport transport;

private BatchStrategy strategy;

public void send(Message message) {
    strategy.newMessage(message);
    List<Message> messages = strategy.getMessagesToSend();

    for (Message each : messages) {
        byte[] bytes = each.toBytes();
        transport.sendBytes(bytes);
    }
    strategy.sent();
}
}

package com.thinkinginobjects;

public class FixSizeBatchStrategy implements BatchStrategy {

private static final int BATCH_SIZE = 0;
private List<Message> buffer = new ArrayList<Message>();

@Override
public void newMessage(Message message) {
    buffer.add(message);    
}

@Override
public List<Message> getMessagesToSend() {
    if (buffer.size() == BATCH_SIZE) {
        return buffer;
    } else {
        return Collections.emptyList();
    }
}

@Override
public void sent() {
    buffer.clear(); 
}

}

为了完成这个故事,几天后我收到了一个要求,每5秒发送一次批次的消息。我的猜测是正确的,我可以通过添加扩展来适应需求,而不是修改我的代码:

代码语言:javascript
运行
复制
package com.thinkinginobjects;

public class FixIntervalBatchStrategy implements BatchStrategy {

private static final long INTERVAL = 5000;

private List<Message> buffer = new ArrayList<Message>();

private volatile boolean readyToSend;

public FixIntervalBatchStrategy() {
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
    executorService.scheduleAtFixedRate(new Runnable() {

        @Override
        public void run() {
            readyToSend = true;

        }
    }, 0, INTERVAL, TimeUnit.MILLISECONDS);
}

@Override
public void newMessage(Message message) {
    buffer.add(message);
}

@Override
public List<Message> getMessagesToSend() {
    if (readyToSend) {
        return buffer;
    } else {
        return Collections.emptyList();
    }
}

@Override
public void sent() {
    readyToSend = false;
    buffer.clear();
}
}
  • 免责声明:代码示例属于www.thinkingInObjects.com
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12255812

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档