I have this code
public class DoubleSensor: ObservableObject {
private var cancellables: Set<AnyCancellable> = Set<AnyCancellable>()
private(set) var sensor: any VEntity
@Published public var state: doubleState = DefaultState.forDouble()
public init(withSensor sensor: any VEntity) {
self.sensor = sensor
}
private func updateData(fromState newState: doubleState) async {
self.state = newState
}
}
public final class TemperatureSensor: DoubleSensor {
public var measurement: Measurement<UnitTemperature> {
return Measurement(value: state.value, unit: .celsius)
}
public override init(withSensor sensor: any VEntity) {
super.init(withSensor: sensor)
}
}
public final class PercentageSensor: DoubleSensor {
public var measurement: Measurement<UnitPercentage> {
return Measurement(value: state.value, unit: UnitPercentage.percentage)
}
public override init(withSensor sensor: any VEntity) {
super.init(withSensor: sensor)
}
}
public final class EnergySensor: DoubleSensor {
public var measurement: Measurement<UnitEnergy> {
return Measurement(value: state.value, unit: .wattHours)
}
public override init(withSensor sensor: any VEntity) {
super.init(withSensor: sensor)
}
}
As you can see I have 3 class inheriting from DoubleSensor
class (a small version of it). All of inheriting classes have a measurement variable specific to a measurement unit.
How can I create a generic class instead specific ones?
I can create something like
public final class MeasurementSensor<T: Dimension>: DoubleSensor {
public var measurement: Measurement<T> {
return Measurement(value: state.value, unit: ???)
}
public override init(withSensor sensor: any VEntity) {
super.init(withSensor: sensor)
}
}
but I don't know how to set the unit value
Edit:
Thanks to Dávid Pásztor to suggesting me edits to improve the question:
VEntity
is a protocol defined as
public protocol VEntity: Hashable, Equatable {
var domain: String { get }
var entityId: String { get }
var entityName: String { get }
var notificationName: NSNotification.Name { get }
}
doubleState
is a typealias defined as
public typealias doubleState = EntityState<Double, GenericAttributes>
where EntityState
is an object representing an entity state with two generics properties: S (value) and A (attributes), but I don't think its definition (not small) is useful in this context
and GeneriAttribute
is
public struct GenericAttributes: VAttribute {
public let commonName: String
}
are your DoubleSensor subclasses only supposed to work with a hardcoded unit value? or should they work with any value of the same type?
My goal is to get rid of multiple inheriting classes and create just one that will contain a measurement of given unit. Ex:
let temperatureSensor: MeasurementSensor = MeasurementSensor(withSensor: sensor01, andUnit: UnitTemperature, measuringIn: .celsius)
let energySensor: MeasurementSensor = MeasurementSensor(withSensor: sensor02, andUnit: UnitEnergy, measuringIn: .kilowattHours)
This is just pseudocode to give an idea of final result. I hope now question is more clear.
Edit 2:
Suggested by Alexander (thanks) I think we can cut off all irrelevant stuff keeping only what we need, so we can use this class
public final class MeasurementSensor {
var value: Double
public var measurement: Measurement<UnitEnergy> {
return Measurement(value: value, unit: .kilowattHours)
}
init(value: Double) {
self.value = value
}
}
as example, but keeping that pseudocode above as a final result
If you want a generic class where the measurement unit is of a certain type, you simply need to make your class generic over the Dimension
type and inject the actual unit you want to use when creating a new instance.
final class MeasurementSensor<UnitType: Dimension> {
var value: Double
var unit: UnitType
var measurement: Measurement<UnitType> {
return Measurement(value: value, unit: unit)
}
init(value: Double, unit: UnitType) {
self.value = value
self.unit = unit
}
}
Usage:
let kwhSensor = MeasurementSensor(value: 0, unit: UnitEnergy.kilowattHours)
let celsiusSensor = MeasurementSensor(value: 0, unit: UnitTemperature.celsius)