首页 \ 问答 \ 正确的程序结构(Correct program structure)

正确的程序结构(Correct program structure)

我的应用程序用于与电子设备通信。 它会读取一些识别数据(如设备固件版本),一些配置数据以及来自传感器的周期性数据。 计划分为三层:

  1. 数据层 - 描述数据如何存储在设备存储器中的简单结构。

  2. 业务层 - 用于与设备通信的类。 它们包含来自数据层的结构,并在读取和写入设备时使用它们来存储数据。

  3. 表示层 - 用户界面(WinForms); 使用businnes图层类。

假使,假设:

数据结构如下:

public struct Configuration
{
 public int Option1;
 public int Option2;
}

public struct Visualization
{
 public int Temperature;
 public int Pressure;
}

业务层类包装这些结构并包含通信逻辑:

public abstract class BaseEntity<DataStructureType>
{
 protected DataStructureType dataStructure;
 public BaseEntity()
 {
  this.dataStructure = new DataStructureType();
 }
 /*
  device communication logic
 */
 public abstract bool GetAllData();
}

public class ConfigurationEntity : BaseEntity<Configuration>
{
 public override bool GetAllData()
 {
  //getting configuration data from device
 }
 public int Option1
 {
  get { return this.dataStructure.Option1; }
  set { this.dataStructure.Option1 = value; }
 }
 public int Option2;
 {
  get { return this.dataStructure.Option2 * 100; }
  set { this.dataStructure.Option1 = value / 100; }
 }
}

public class VisualizationEntity : BaseEntity<Visualization>
{
 public override bool GetAllData()
 {
  //getting visualization data from device
 }
 public int Temperature
 {
  get { return this.dataStructure.temperature; }
 }
 public float Pressure;
 {
  get { return Conversions.IntToPressure(this.dataStructure.pressure); }
 }
}

和Conversions类用于转换二进制数据:

public static class Conversions
{
 public static float IntToPressure(int parameter)
 {
  return PressureAlgorithmA(parameter);
 }
 private static float PressureAlgorithmA(int parameter)
 {
  //some algorithm (called A) to convert binary pressure to pressure in bars
 }
}

问题是新的固件版本,因为应用程序应该处理两个设备版本(旧版本和更新版本)。 新版本已更新,包括几个新结构,新转换算法,新配置选项。 看起来像:

public struct Configuration
{
 /*
  old options are here
 */
 //and updated goes here:
 public int Option3;
 public int Option4;
}

public class ConfigurationEntity : BaseEntity<Configuration>
{
 /*
  old code is here
 */
 //and updated goes here
 public int Option3
 {
  get { return this.dataStructure.Option3; }
  set { this.dataStructure.Option3 = value; }
 }
 public int Option4;
 {
  get { return this.dataStructure.Option4 * 20; }
  set { this.dataStructure.Option4 = value / 20; }
 }
}

转换也改变了:

public static class Conversions
{
 public static float IntToPressure(int parameter)
 {
  return PressureAlgorithmB(parameter);
 }
 private static float PressureAlgorithmB(int parameter)
 {
  //some algorithm (called B) to convert binary pressure to pressure in bars
 }
}

现在我每次需要使用新功能时都要检查设备版本(当从Configuration更改Option3或Option4时,或者当我需要使用新数据etities或在向用户显示压力时使用哪种算法)。

我的问题是如何使用OOP实践来做到这一点? 在C#中执行此操作的正确方法是什么?

我在考虑工厂模式,但配置中的新选项或新数据实体是什么?


My application is used for communication with electronic device. It reads some identification data (like device firmware version), some configuration data, and periodically data from sensors. Program is divided into three layers:

  1. Data layer - simple structures describing how data are stored in device memory.

  2. Business layer - classes used for communication with device. They contains structures from data layer and using them to store data when reading from and writing to device.

  3. Presentation layer - user interface (WinForms); using businnes layer classes.

Assume that:

Data structures looks like:

public struct Configuration
{
 public int Option1;
 public int Option2;
}

public struct Visualization
{
 public int Temperature;
 public int Pressure;
}

Business layer classes wraps these structures and contains logic for communication:

public abstract class BaseEntity<DataStructureType>
{
 protected DataStructureType dataStructure;
 public BaseEntity()
 {
  this.dataStructure = new DataStructureType();
 }
 /*
  device communication logic
 */
 public abstract bool GetAllData();
}

public class ConfigurationEntity : BaseEntity<Configuration>
{
 public override bool GetAllData()
 {
  //getting configuration data from device
 }
 public int Option1
 {
  get { return this.dataStructure.Option1; }
  set { this.dataStructure.Option1 = value; }
 }
 public int Option2;
 {
  get { return this.dataStructure.Option2 * 100; }
  set { this.dataStructure.Option1 = value / 100; }
 }
}

public class VisualizationEntity : BaseEntity<Visualization>
{
 public override bool GetAllData()
 {
  //getting visualization data from device
 }
 public int Temperature
 {
  get { return this.dataStructure.temperature; }
 }
 public float Pressure;
 {
  get { return Conversions.IntToPressure(this.dataStructure.pressure); }
 }
}

And Conversions class used to convert binary data:

public static class Conversions
{
 public static float IntToPressure(int parameter)
 {
  return PressureAlgorithmA(parameter);
 }
 private static float PressureAlgorithmA(int parameter)
 {
  //some algorithm (called A) to convert binary pressure to pressure in bars
 }
}

Problem is new firmware version, because application should handle both device versions(older and newer). New version has been updated with couple of new structures to read, new conversion algorithms, new configuration options. It looks like:

public struct Configuration
{
 /*
  old options are here
 */
 //and updated goes here:
 public int Option3;
 public int Option4;
}

public class ConfigurationEntity : BaseEntity<Configuration>
{
 /*
  old code is here
 */
 //and updated goes here
 public int Option3
 {
  get { return this.dataStructure.Option3; }
  set { this.dataStructure.Option3 = value; }
 }
 public int Option4;
 {
  get { return this.dataStructure.Option4 * 20; }
  set { this.dataStructure.Option4 = value / 20; }
 }
}

Also Conversions has beem changed:

public static class Conversions
{
 public static float IntToPressure(int parameter)
 {
  return PressureAlgorithmB(parameter);
 }
 private static float PressureAlgorithmB(int parameter)
 {
  //some algorithm (called B) to convert binary pressure to pressure in bars
 }
}

Now I have to check for device version every time I need to use new funcionality (when changing Option3 or Option4 from Configuration or when I need to use new data etities or which algorithm use when showing pressure to user).

My question is how can I do that with OOP practicies? What is correct way to do this in C#?

I was thinking about factory pattern, but what with new options in Configuration, or with new data entities?


原文:https://stackoverflow.com/questions/10190781
更新时间:2023-11-25 13:11

最满意答案

将相同的样式应用于UIButton多个实例:


严格的程序化路线:

前两种方法就是我要做的。 第三个是为了说明可以编写一个从另一个按钮复制设置的init

使用子类应用预设样式:

class StyledButton : UIButton {        

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = UIColor.blackColor()
        // more styling
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

将预设样式应用于UIButton的扩展名:

extension UIButton {

    func setCustomStyle1() {

        self.backgroundColor = UIColor.blackColor()
        // nore styling

    }
}

在UIButton的扩展中使用便利init复制样式:

extension UIButton {

    convenience init(styleFromButton button: UIButton, frame: CGRect) {

        self.init(frame: frame)

        self.backgroundColor = button.backgroundColor

    }
}

Interface Builder解决方案:

创建一个新的Swift文件:

在此处输入图像描述 在此处输入图像描述

在新文件中创建UIButton的子类:

class StyledButton : UIButton {

    override init(frame: CGRect) {
        super.init(frame: frame)
        style()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        style()
    }

    private func style() {
        self.backgroundColor = UIColor.blackColor()
        // more styling
    }
}

返回Interface Builder并选择要设置样式的UIButton 。 选择右侧的第三个面板,这是身份检查器 。 选择子类作为UIButton的类。

重复所有按钮以设置样式。

在此处输入图像描述


或者在IB和Alt-Drag中设置整个内容的样式以制作副本。


Applying the same style to multiple instances of UIButton:


Strictly Programmatic route:

The first two methods are what I would do. The third is only to illustrate that it is possible to write an init that copies settings from another button.

Apply preset style with a sub class:

class StyledButton : UIButton {        

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = UIColor.blackColor()
        // more styling
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Apply preset style with an extension to UIButton:

extension UIButton {

    func setCustomStyle1() {

        self.backgroundColor = UIColor.blackColor()
        // nore styling

    }
}

Copy style with a convenience init in an extension to UIButton:

extension UIButton {

    convenience init(styleFromButton button: UIButton, frame: CGRect) {

        self.init(frame: frame)

        self.backgroundColor = button.backgroundColor

    }
}

Interface Builder solution:

Create a new Swift file:

enter image description here enter image description here

Create a sub class of UIButton in the new file:

class StyledButton : UIButton {

    override init(frame: CGRect) {
        super.init(frame: frame)
        style()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        style()
    }

    private func style() {
        self.backgroundColor = UIColor.blackColor()
        // more styling
    }
}

Go back to the Interface Builder and select a UIButton you want to style. Select the third panel on the right, this is the identity inspector. Select your sub class as the class for the UIButton.

Repeat for all buttons to style.

enter image description here


Or style the entire thing in IB and Alt-Drag to make a copy.

相关问答

更多

相关文章

更多

最新问答

更多
  • h2元素推动其他h2和div。(h2 element pushing other h2 and div down. two divs, two headers, and they're wrapped within a parent div)
  • 创建一个功能(Create a function)
  • 我投了份简历,是电脑编程方面的学徒,面试时说要培训三个月,前面
  • PDO语句不显示获取的结果(PDOstatement not displaying fetched results)
  • Qt冻结循环的原因?(Qt freezing cause of the loop?)
  • TableView重复youtube-api结果(TableView Repeating youtube-api result)
  • 如何使用自由职业者帐户登录我的php网站?(How can I login into my php website using freelancer account? [closed])
  • SQL Server 2014版本支持的最大数据库数(Maximum number of databases supported by SQL Server 2014 editions)
  • 我如何获得DynamicJasper 3.1.2(或更高版本)的Maven仓库?(How do I get the maven repository for DynamicJasper 3.1.2 (or higher)?)
  • 以编程方式创建UITableView(Creating a UITableView Programmatically)
  • 如何打破按钮上的生命周期循环(How to break do-while loop on button)
  • C#使用EF访问MVC上的部分类的自定义属性(C# access custom attributes of a partial class on MVC with EF)
  • 如何获得facebook app的publish_stream权限?(How to get publish_stream permissions for facebook app?)
  • 如何防止调用冗余函数的postgres视图(how to prevent postgres views calling redundant functions)
  • Sql Server在欧洲获取当前日期时间(Sql Server get current date time in Europe)
  • 设置kotlin扩展名(Setting a kotlin extension)
  • 如何并排放置两个元件?(How to position two elements side by side?)
  • 如何在vim中启用python3?(How to enable python3 in vim?)
  • 在MySQL和/或多列中使用多个表用于Rails应用程序(Using multiple tables in MySQL and/or multiple columns for a Rails application)
  • 如何隐藏谷歌地图上的登录按钮?(How to hide the Sign in button from Google maps?)
  • Mysql左连接旋转90°表(Mysql Left join rotate 90° table)
  • dedecms如何安装?
  • 在哪儿学计算机最好?
  • 学php哪个的书 最好,本人菜鸟
  • 触摸时不要突出显示表格视图行(Do not highlight table view row when touched)
  • 如何覆盖错误堆栈getter(How to override Error stack getter)
  • 带有ImageMagick和许多图像的GIF动画(GIF animation with ImageMagick and many images)
  • USSD INTERFACE - > java web应用程序通信(USSD INTERFACE -> java web app communication)
  • 电脑高中毕业学习去哪里培训
  • 正则表达式验证SMTP响应(Regex to validate SMTP Responses)